diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/torture/vfs | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/torture/vfs')
-rw-r--r-- | source4/torture/vfs/acl_xattr.c | 281 | ||||
-rw-r--r-- | source4/torture/vfs/fruit.c | 8839 | ||||
-rw-r--r-- | source4/torture/vfs/vfs.c | 123 |
3 files changed, 9243 insertions, 0 deletions
diff --git a/source4/torture/vfs/acl_xattr.c b/source4/torture/vfs/acl_xattr.c new file mode 100644 index 0000000..1deb2b3 --- /dev/null +++ b/source4/torture/vfs/acl_xattr.c @@ -0,0 +1,281 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Ralph Boehme 2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/cmdline/cmdline.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "libcli/smb/smbXcli_base.h" +#include "torture/torture.h" +#include "torture/vfs/proto.h" +#include "libcli/resolve/resolve.h" +#include "torture/util.h" +#include "torture/smb2/proto.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "lib/param/param.h" + +#define BASEDIR "smb2-testsd" + +#define CHECK_SECURITY_DESCRIPTOR(_sd1, _sd2) do { \ + if (!security_descriptor_equal(_sd1, _sd2)) { \ + torture_warning(tctx, "security descriptors don't match!\n"); \ + torture_warning(tctx, "got:\n"); \ + NDR_PRINT_DEBUG(security_descriptor, _sd1); \ + torture_warning(tctx, "expected:\n"); \ + NDR_PRINT_DEBUG(security_descriptor, _sd2); \ + torture_result(tctx, TORTURE_FAIL, \ + "%s: security descriptors don't match!\n", \ + __location__); \ + ret = false; \ + } \ +} while (0) + +static bool test_default_acl_posix(struct torture_context *tctx, + struct smb2_tree *tree_unused) +{ + struct smb2_tree *tree = NULL; + NTSTATUS status; + bool ok; + bool ret = true; + const char *dname = BASEDIR "\\testdir"; + const char *fname = BASEDIR "\\testdir\\testfile"; + struct smb2_handle fhandle = {{0}}; + struct smb2_handle dhandle = {{0}}; + union smb_fileinfo q; + union smb_setfileinfo set; + struct security_descriptor *sd = NULL; + struct security_descriptor *exp_sd = NULL; + char *owner_sid = NULL; + char *group_sid = NULL; + + ok = torture_smb2_con_share(tctx, "acl_xattr_ign_sysacl_posix", &tree); + torture_assert_goto(tctx, ok == true, ret, done, + "Unable to connect to 'acl_xattr_ign_sysacl_posix'\n"); + + ok = smb2_util_setup_dir(tctx, tree, BASEDIR); + torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n"); + + ZERO_STRUCT(dhandle); + status = torture_smb2_testdir(tree, dname, &dhandle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); + + torture_comment(tctx, "Get the original sd\n"); + + ZERO_STRUCT(q); + q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + q.query_secdesc.in.file.handle = dhandle; + q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; + status = smb2_getinfo_file(tree, tctx, &q); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); + + sd = q.query_secdesc.out.sd; + owner_sid = dom_sid_string(tctx, sd->owner_sid); + group_sid = dom_sid_string(tctx, sd->group_sid); + torture_comment(tctx, "owner [%s] group [%s]\n", owner_sid, group_sid); + + torture_comment(tctx, "Set ACL with no inheritable ACE\n"); + + sd = security_descriptor_dacl_create(tctx, + 0, NULL, NULL, + owner_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_DIR_ALL, + 0, + NULL); + + ZERO_STRUCT(set); + set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + set.set_secdesc.in.file.handle = dhandle; + set.set_secdesc.in.secinfo_flags = SECINFO_DACL; + set.set_secdesc.in.sd = sd; + status = smb2_setinfo_file(tree, &set); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file\n"); + + TALLOC_FREE(sd); + smb2_util_close(tree, dhandle); + + torture_comment(tctx, "Create file\n"); + + ZERO_STRUCT(fhandle); + status = torture_smb2_testfile(tree, fname, &fhandle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_complex_file\n"); + + torture_comment(tctx, "Query file SD\n"); + + ZERO_STRUCT(q); + q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + q.query_secdesc.in.file.handle = fhandle; + q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; + status = smb2_getinfo_file(tree, tctx, &q); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); + sd = q.query_secdesc.out.sd; + + smb2_util_close(tree, fhandle); + ZERO_STRUCT(fhandle); + + torture_comment(tctx, "Checking actual file SD against expected SD\n"); + + exp_sd = security_descriptor_dacl_create( + tctx, 0, owner_sid, group_sid, + owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, + group_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0, + SID_WORLD, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_READ|FILE_GENERIC_WRITE|FILE_GENERIC_EXECUTE, 0, + SID_NT_SYSTEM, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, + NULL); + + CHECK_SECURITY_DESCRIPTOR(sd, exp_sd); + +done: + if (!smb2_util_handle_empty(fhandle)) { + smb2_util_close(tree, fhandle); + } + if (!smb2_util_handle_empty(dhandle)) { + smb2_util_close(tree, dhandle); + } + if (tree != NULL) { + smb2_deltree(tree, BASEDIR); + smb2_tdis(tree); + } + + return ret; +} + +static bool test_default_acl_win(struct torture_context *tctx, + struct smb2_tree *tree_unused) +{ + struct smb2_tree *tree = NULL; + NTSTATUS status; + bool ok; + bool ret = true; + const char *dname = BASEDIR "\\testdir"; + const char *fname = BASEDIR "\\testdir\\testfile"; + struct smb2_handle fhandle = {{0}}; + struct smb2_handle dhandle = {{0}}; + union smb_fileinfo q; + union smb_setfileinfo set; + struct security_descriptor *sd = NULL; + struct security_descriptor *exp_sd = NULL; + char *owner_sid = NULL; + char *group_sid = NULL; + + ok = torture_smb2_con_share(tctx, "acl_xattr_ign_sysacl_windows", &tree); + torture_assert_goto(tctx, ok == true, ret, done, + "Unable to connect to 'acl_xattr_ign_sysacl_windows'\n"); + + ok = smb2_util_setup_dir(tctx, tree, BASEDIR); + torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n"); + + ZERO_STRUCT(dhandle); + status = torture_smb2_testdir(tree, dname, &dhandle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); + + torture_comment(tctx, "Get the original sd\n"); + + ZERO_STRUCT(q); + q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + q.query_secdesc.in.file.handle = dhandle; + q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; + status = smb2_getinfo_file(tree, tctx, &q); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); + + sd = q.query_secdesc.out.sd; + owner_sid = dom_sid_string(tctx, sd->owner_sid); + group_sid = dom_sid_string(tctx, sd->group_sid); + torture_comment(tctx, "owner [%s] group [%s]\n", owner_sid, group_sid); + + torture_comment(tctx, "Set ACL with no inheritable ACE\n"); + + sd = security_descriptor_dacl_create(tctx, + 0, NULL, NULL, + owner_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_DIR_ALL, + 0, + NULL); + + ZERO_STRUCT(set); + set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + set.set_secdesc.in.file.handle = dhandle; + set.set_secdesc.in.secinfo_flags = SECINFO_DACL; + set.set_secdesc.in.sd = sd; + status = smb2_setinfo_file(tree, &set); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file\n"); + + TALLOC_FREE(sd); + smb2_util_close(tree, dhandle); + + torture_comment(tctx, "Create file\n"); + + ZERO_STRUCT(fhandle); + status = torture_smb2_testfile(tree, fname, &fhandle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_complex_file\n"); + + torture_comment(tctx, "Query file SD\n"); + + ZERO_STRUCT(q); + q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + q.query_secdesc.in.file.handle = fhandle; + q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER | SECINFO_GROUP; + status = smb2_getinfo_file(tree, tctx, &q); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file\n"); + sd = q.query_secdesc.out.sd; + + smb2_util_close(tree, fhandle); + ZERO_STRUCT(fhandle); + + torture_comment(tctx, "Checking actual file SD against expected SD\n"); + + exp_sd = security_descriptor_dacl_create( + tctx, 0, owner_sid, group_sid, + owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, + SID_NT_SYSTEM, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_RIGHTS_FILE_ALL, 0, + NULL); + + CHECK_SECURITY_DESCRIPTOR(sd, exp_sd); + +done: + if (!smb2_util_handle_empty(fhandle)) { + smb2_util_close(tree, fhandle); + } + if (!smb2_util_handle_empty(dhandle)) { + smb2_util_close(tree, dhandle); + } + if (tree != NULL) { + smb2_deltree(tree, BASEDIR); + smb2_tdis(tree); + } + + return ret; +} + +/* + basic testing of vfs_acl_xattr +*/ +struct torture_suite *torture_acl_xattr(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "acl_xattr"); + + torture_suite_add_1smb2_test(suite, "default-acl-style-posix", test_default_acl_posix); + torture_suite_add_1smb2_test(suite, "default-acl-style-windows", test_default_acl_win); + + suite->description = talloc_strdup(suite, "vfs_acl_xattr tests"); + + return suite; +} diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c new file mode 100644 index 0000000..b9cab0c --- /dev/null +++ b/source4/torture/vfs/fruit.c @@ -0,0 +1,8839 @@ +/* + Unix SMB/CIFS implementation. + + vfs_fruit tests + + Copyright (C) Ralph Boehme 2014 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "libcli/libcli.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "libcli/smb/smb2_create_ctx.h" +#include "lib/cmdline/cmdline.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" +#include "MacExtensions.h" +#include "lib/util/tsort.h" + +#include "torture/torture.h" +#include "torture/util.h" +#include "torture/smb2/proto.h" +#include "torture/vfs/proto.h" +#include "librpc/gen_ndr/ndr_ioctl.h" +#include "libcli/security/dom_sid.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "libcli/security/secace.h" +#include "libcli/security/security_descriptor.h" + +#define BASEDIR "vfs_fruit_dir" +#define FNAME_CC_SRC "testfsctl.dat" +#define FNAME_CC_DST "testfsctl2.dat" + +#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) + +#define CHECK_VALUE(v, correct) do { \ + if ((v) != (correct)) { \ + torture_result(tctx, TORTURE_FAIL, \ + "(%s) Incorrect value %s=%u - should be %u\n", \ + __location__, #v, (unsigned)v, (unsigned)correct); \ + ret = false; \ + goto done; \ + }} while (0) + +static bool check_stream_list(struct smb2_tree *tree, + struct torture_context *tctx, + const char *fname, + int num_exp, + const char **exp, + bool is_dir); + +static int qsort_string(char * const *s1, char * const *s2) +{ + return strcmp(*s1, *s2); +} + +static int qsort_stream(const struct stream_struct * s1, const struct stream_struct *s2) +{ + return strcmp(s1->stream_name.s, s2->stream_name.s); +} + +/* + * 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 +}; + +/* +The buf below contains the following AppleDouble encoded data: + +------------------------------------------------------------------------------- +MagicNumber: 00051607 : AppleDouble +Version : 00020000 : Version 2 +Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X +Num. of ent: 0002 : 2 + +------------------------------------------------------------------------------- +Entry ID : 00000009 : Finder Info +Offset : 00000032 : 50 +Length : 00000EB0 : 3760 + +-FInfo-----: +Type : 54455354 : TEST +Creator : 534C4F57 : SLOW +isAlias : 0 +Invisible : 0 +hasBundle : 0 +nameLocked : 0 +Stationery : 0 +CustomIcon : 0 +Reserved : 0 +Inited : 0 +NoINITS : 0 +Shared : 0 +SwitchLaunc: 0 +Hidden Ext : 0 +color : 100 : blue +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 + +-EA--------: +pad : 0000 : .. +magic : 41545452 : ATTR +debug_tag : 53D4580C : 1406425100 +total_size : 00000EE2 : 3810 +data_start : 000000BC : 188 +data_length: 0000005E : 94 +reserved[0]: 00000000 : .... +reserved[1]: 00000000 : .... +reserved[2]: 00000000 : .... +flags : 0000 : .. +num_attrs : 0002 : 2 +-EA ENTRY--: +offset : 000000BC : 188 +length : 0000005B : 91 +flags : 0000 : .. +namelen : 24 : 36 +-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 61 : com.apple.metada +00000010 : 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 54 : ta:_kMDItemUserT +00000020 : 61 67 73 00 : ags. +-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 62 70 6C 69 73 74 30 30 A5 01 02 03 04 05 54 74 : bplist00......Tt +00000010 : 65 73 74 66 00 47 00 72 00 FC 00 6E 00 0A 00 32 : estf.G.r...n...2 +00000020 : 56 4C 69 6C 61 0A 33 56 47 65 6C 62 0A 35 56 42 : VLila.3VGelb.5VB +00000030 : 6C 61 75 0A 34 08 0E 13 20 27 2E 00 00 00 00 00 : lau.4... '...... +00000040 : 00 01 01 00 00 00 00 00 00 00 06 00 00 00 00 00 : ................ +00000050 : 00 00 00 00 00 00 00 00 00 00 35 : ..........5 +-EA ENTRY--: +offset : 00000117 : 279 +length : 00000003 : 3 +flags : 0000 : .. +namelen : 08 : 8 +-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 66 6F 6F 3A 62 61 72 00 : foo:bar. +-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 62 61 7A : baz + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 54 45 53 54 53 4C 4F 57 00 08 00 00 00 00 00 00 : TESTSLOW........ +00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000020 : 00 00 41 54 54 52 53 D4 58 0C 00 00 0E E2 00 00 : ..ATTRS.X....... +00000030 : 00 BC 00 00 00 5E 00 00 00 00 00 00 00 00 00 00 : .....^.......... +00000040 : 00 00 00 00 00 02 00 00 00 BC 00 00 00 5B 00 00 : .............[.. +00000050 : 24 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 : $com.apple.metad +00000060 : 61 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 : ata:_kMDItemUser +00000070 : 54 61 67 73 00 00 00 00 01 17 00 00 00 03 00 00 : Tags............ +00000080 : 08 66 6F 6F 3A 62 61 72 00 66 62 70 6C 69 73 74 : .foo:bar.fbplist +00000090 : 30 30 A5 01 02 03 04 05 54 74 65 73 74 66 00 47 : 00......Ttestf.G +000000A0 : 00 72 00 FC 00 6E 00 0A 00 32 56 4C 69 6C 61 0A : .r...n...2VLila. +000000B0 : 33 56 47 65 6C 62 0A 35 56 42 6C 61 75 0A 34 08 : 3VGelb.5VBlau.4. +000000C0 : 0E 13 20 27 2E 00 00 00 00 00 00 01 01 00 00 00 : .. '............ +000000D0 : 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 35 62 61 7A 00 00 00 00 00 00 00 00 : ....5baz........ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +... all zeroes ... +00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + +------------------------------------------------------------------------------- +Entry ID : 00000002 : Resource Fork +Offset : 00000EE2 : 3810 +Length : 0000011E : 286 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000010 : 54 68 69 73 20 72 65 73 6F 75 72 63 65 20 66 6F : This resource fo +00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally +00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank .. +00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : .............. + +It was created with: +$ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"' +*/ +static char osx_adouble_w_xattr[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00, + 0x01, 0x1e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x4c, + 0x4f, 0x57, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52, + 0x53, 0xd4, 0x58, 0x0c, 0x00, 0x00, 0x0e, 0xe2, + 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5f, 0x6b, + 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x55, 0x73, + 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x3a, 0x62, + 0x61, 0x72, 0x00, 0x66, 0x62, 0x70, 0x6c, 0x69, + 0x73, 0x74, 0x30, 0x30, 0xa5, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x54, 0x74, 0x65, 0x73, 0x74, 0x66, + 0x00, 0x47, 0x00, 0x72, 0x00, 0xfc, 0x00, 0x6e, + 0x00, 0x0a, 0x00, 0x32, 0x56, 0x4c, 0x69, 0x6c, + 0x61, 0x0a, 0x33, 0x56, 0x47, 0x65, 0x6c, 0x62, + 0x0a, 0x35, 0x56, 0x42, 0x6c, 0x61, 0x75, 0x0a, + 0x34, 0x08, 0x0e, 0x13, 0x20, 0x27, 0x2e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x62, + 0x61, 0x7a, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, + 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20, + 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff +}; + +/* + * The buf below contains the following AppleDouble encoded data: + * + * ------------------------------------------------------------------------------- + * MagicNumber: 00051607 : AppleDouble + * Version : 00020000 : Version 2 + * Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X + * Num. of ent: 0002 : 2 + * + * ------------------------------------------------------------------------------- + * Entry ID : 00000002 : Resource Fork + * Offset : 00000052 : 82 + * Length : 0000011E : 286 + * + * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) + * 00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ + * 00000010 : F0 F1 F2 F3 F5 F5 F6 F7 F8 F9 FA FB FC FD FE FF : ................ + * 00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally + * 00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank .. + * 00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ + * 00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : .............. + * + * Entry ID : 00000009 : Finder Info + * Offset : 00000032 : 50 + * Length : 00000020 : 32 + * + * -NOTE------: cannot detect whether FInfo or DInfo. assume FInfo. + * + * -FInfo-----: + * Type : 57415645 : WAVE + * Creator : 5054756C : PTul + * isAlias : 0 + * Invisible : 0 + * 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 : 57 41 56 45 50 54 75 6C 00 00 00 00 00 00 00 00 : WAVEPTul........ + * 00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * * + * It was created with: + * $ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"' + */ +static char osx_adouble_without_xattr[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x52, 0x00, 0x00, 0x01, 0x1e, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, + 0x00, 0x20, 0x57, 0x41, 0x56, 0x45, 0x50, 0x54, + 0x75, 0x6c, 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, + 0xfe, 0xff, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, + 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20, + 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff +}; + +/* +The buf below contains the following AppleDouble encoded data: + +------------------------------------------------------------------------------- +MagicNumber: 00051607 : AppleDouble +Version : 00020000 : Version 2 +Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X +Num. of ent: 0002 : 2 + +------------------------------------------------------------------------------- +Entry ID : 00000009 : Finder Info +Offset : 00000032 : 50 +Length : 00000EB0 : 3760 + +-FInfo-----: +Type : 54455354 : TEST +Creator : 534C4F57 : SLOW +isAlias : 0 +Invisible : 0 +hasBundle : 0 +nameLocked : 0 +Stationery : 0 +CustomIcon : 0 +Reserved : 0 +Inited : 0 +NoINITS : 0 +Shared : 0 +SwitchLaunc: 0 +Hidden Ext : 0 +color : 100 : blue +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 + +-EA--------: +pad : 0000 : .. +magic : 41545452 : ATTR +debug_tag : 53D4580C : 1406425100 +total_size : 00000EE2 : 3810 +data_start : 000000BC : 188 +data_length: 0000005E : 94 +reserved[0]: 00000000 : .... +reserved[1]: 00000000 : .... +reserved[2]: 00000000 : .... +flags : 0000 : .. +num_attrs : 0002 : 2 +-EA ENTRY--: +offset : 000000BC : 188 +length : 0000005B : 91 +flags : 0000 : .. +namelen : 24 : 36 +-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 61 : com.apple.metada +00000010 : 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 54 : ta:_kMDItemUserT +00000020 : 61 67 73 00 : ags. +-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 62 70 6C 69 73 74 30 30 A5 01 02 03 04 05 54 74 : bplist00......Tt +00000010 : 65 73 74 66 00 47 00 72 00 FC 00 6E 00 0A 00 32 : estf.G.r...n...2 +00000020 : 56 4C 69 6C 61 0A 33 56 47 65 6C 62 0A 35 56 42 : VLila.3VGelb.5VB +00000030 : 6C 61 75 0A 34 08 0E 13 20 27 2E 00 00 00 00 00 : lau.4... '...... +00000040 : 00 01 01 00 00 00 00 00 00 00 06 00 00 00 00 00 : ................ +00000050 : 00 00 00 00 00 00 00 00 00 00 35 : ..........5 +-EA ENTRY--: +offset : 00000117 : 279 +length : 00000003 : 3 +flags : 0000 : .. +namelen : 08 : 8 +-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 66 6F 6F 3A 62 61 72 00 : foo:bar. +-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 62 61 7A : baz + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 54 45 53 54 53 4C 4F 57 00 08 00 00 00 00 00 00 : TESTSLOW........ +00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000020 : 00 00 41 54 54 52 53 D4 58 0C 00 00 0E E2 00 00 : ..ATTRS.X....... +00000030 : 00 BC 00 00 00 5E 00 00 00 00 00 00 00 00 00 00 : .....^.......... +00000040 : 00 00 00 00 00 02 00 00 00 BC 00 00 00 5B 00 00 : .............[.. +00000050 : 24 63 6F 6D 2E 61 70 70 6C 65 2E 6D 65 74 61 64 : $com.apple.metad +00000060 : 61 74 61 3A 5F 6B 4D 44 49 74 65 6D 55 73 65 72 : ata:_kMDItemUser +00000070 : 54 61 67 73 00 00 00 00 01 17 00 00 00 03 00 00 : Tags............ +00000080 : 08 66 6F 6F 3A 62 61 72 00 66 62 70 6C 69 73 74 : .foo:bar.fbplist +00000090 : 30 30 A5 01 02 03 04 05 54 74 65 73 74 66 00 47 : 00......Ttestf.G +000000A0 : 00 72 00 FC 00 6E 00 0A 00 32 56 4C 69 6C 61 0A : .r...n...2VLila. +000000B0 : 33 56 47 65 6C 62 0A 35 56 42 6C 61 75 0A 34 08 : 3VGelb.5VBlau.4. +000000C0 : 0E 13 20 27 2E 00 00 00 00 00 00 01 01 00 00 00 : .. '............ +000000D0 : 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 35 62 61 7A 00 00 00 00 00 00 00 00 : ....5baz........ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +... all zeroes ... +00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + +------------------------------------------------------------------------------- +Entry ID : 00000002 : Resource Fork +Offset : 00000EE2 : 3810 +Length : 0000011E : 286 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000010 : F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF : This resource fo +00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally +00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank .. +00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : .............. + +It was created with: +$ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"' +*/ +static char osx_adouble_non_empty_rfork_w_xattr[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00, + 0x01, 0x1e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x4c, + 0x4f, 0x57, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x54, 0x54, 0x52, + 0x53, 0xd4, 0x58, 0x0c, 0x00, 0x00, 0x0e, 0xe2, + 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x5f, 0x6b, + 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x55, 0x73, + 0x65, 0x72, 0x54, 0x61, 0x67, 0x73, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x3a, 0x62, + 0x61, 0x72, 0x00, 0x66, 0x62, 0x70, 0x6c, 0x69, + 0x73, 0x74, 0x30, 0x30, 0xa5, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x54, 0x74, 0x65, 0x73, 0x74, 0x66, + 0x00, 0x47, 0x00, 0x72, 0x00, 0xfc, 0x00, 0x6e, + 0x00, 0x0a, 0x00, 0x32, 0x56, 0x4c, 0x69, 0x6c, + 0x61, 0x0a, 0x33, 0x56, 0x47, 0x65, 0x6c, 0x62, + 0x0a, 0x35, 0x56, 0x42, 0x6c, 0x61, 0x75, 0x0a, + 0x34, 0x08, 0x0e, 0x13, 0x20, 0x27, 0x2e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x62, + 0x61, 0x7a, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, + 0xfe, 0xff, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, + 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20, + 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff +}; + +/** + * talloc and intialize an AfpInfo + **/ +static AfpInfo *torture_afpinfo_new(TALLOC_CTX *mem_ctx) +{ + AfpInfo *info; + + info = talloc_zero(mem_ctx, AfpInfo); + if (info == NULL) { + return NULL; + } + + info->afpi_Signature = AFP_Signature; + info->afpi_Version = AFP_Version; + info->afpi_BackupTime = AFP_BackupTime; + + return info; +} + +/** + * Pack AfpInfo into a talloced buffer + **/ +static char *torture_afpinfo_pack(TALLOC_CTX *mem_ctx, + AfpInfo *info) +{ + char *buf; + + buf = talloc_zero_array(mem_ctx, char, AFP_INFO_SIZE); + if (buf == NULL) { + return NULL; + } + + RSIVAL(buf, 0, info->afpi_Signature); + RSIVAL(buf, 4, info->afpi_Version); + RSIVAL(buf, 12, info->afpi_BackupTime); + memcpy(buf + 16, info->afpi_FinderInfo, sizeof(info->afpi_FinderInfo)); + + return buf; +} + +/** + * Unpack AfpInfo + **/ +#if 0 +static void torture_afpinfo_unpack(AfpInfo *info, char *data) +{ + info->afpi_Signature = RIVAL(data, 0); + info->afpi_Version = RIVAL(data, 4); + info->afpi_BackupTime = RIVAL(data, 12); + memcpy(info->afpi_FinderInfo, (const char *)data + 16, + sizeof(info->afpi_FinderInfo)); +} +#endif + +static bool torture_write_afpinfo(struct smb2_tree *tree, + struct torture_context *tctx, + TALLOC_CTX *mem_ctx, + const char *fname, + AfpInfo *info) +{ + struct smb2_handle handle; + struct smb2_create io; + NTSTATUS status; + const char *full_name; + char *infobuf; + bool ret = true; + + full_name = talloc_asprintf(mem_ctx, "%s%s", fname, AFPINFO_STREAM_NAME); + if (full_name == NULL) { + torture_comment(tctx, "talloc_asprintf error\n"); + return false; + } + ZERO_STRUCT(io); + io.in.desired_access = SEC_FILE_WRITE_DATA; + io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; + io.in.create_options = 0; + io.in.fname = full_name; + + status = smb2_create(tree, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + handle = io.out.file.handle; + + infobuf = torture_afpinfo_pack(mem_ctx, info); + if (infobuf == NULL) { + return false; + } + + status = smb2_util_write(tree, handle, infobuf, 0, AFP_INFO_SIZE); + CHECK_STATUS(status, NT_STATUS_OK); + + smb2_util_close(tree, handle); + +done: + return ret; +} + +/** + * 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; + char *full_name; + bool ret = true; + + 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) { + TALLOC_FREE(full_name); + return true; + } + torture_comment(tctx, "Unable to open stream %s: %s\n", + full_name, nt_errstr(status)); + TALLOC_FREE(full_name); + return false; + } + + handle = create.out.file.handle; + if (value == NULL) { + TALLOC_FREE(full_name); + smb2_util_close(tree, handle); + 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); + + torture_assert_ntstatus_ok_goto( + tctx, status, ret, done, + talloc_asprintf(tctx, "(%s) Failed to read %lu bytes from stream '%s'\n", + location, (long)strlen(value), full_name)); + + torture_assert_goto(tctx, r.out.data.length == read_count, ret, done, + talloc_asprintf(tctx, "smb2_read returned %jd bytes, expected %jd\n", + (intmax_t)r.out.data.length, (intmax_t)read_count)); + + torture_assert_goto( + tctx, memcmp(r.out.data.data + comp_offset, value, comp_count) == 0, + ret, done, + talloc_asprintf(tctx, "(%s) Bad data in stream\n", location)); + +done: + TALLOC_FREE(full_name); + smb2_util_close(tree, handle); + return ret; +} + +/** + * Read 'count' bytes at 'offset' from stream 'fname:sname' and + * compare against buffer 'value' + **/ +static ssize_t read_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) +{ + struct smb2_handle handle; + struct smb2_create create; + struct smb2_read r; + NTSTATUS status; + const char *full_name; + bool ret = true; + + full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname); + if (full_name == NULL) { + torture_comment(tctx, "talloc_asprintf error\n"); + return -1; + } + 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)) { + torture_comment(tctx, "Unable to open stream %s: %s\n", + full_name, nt_errstr(status)); + return -1; + } + + handle = create.out.file.handle; + + 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)) { + CHECK_STATUS(status, NT_STATUS_END_OF_FILE); + } + + smb2_util_close(tree, handle); + +done: + if (ret == false) { + return -1; + } + return r.out.data.length; +} + +/** + * Read 'count' bytes at 'offset' from stream 'fname:sname' and + * compare against buffer 'value' + **/ +static bool write_stream(struct smb2_tree *tree, + const char *location, + struct torture_context *tctx, + TALLOC_CTX *mem_ctx, + const char *fname, + const char *sname, + off_t offset, + size_t size, + const char *value) +{ + struct smb2_handle handle; + struct smb2_create create; + NTSTATUS status; + const char *full_name; + + full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname ? sname : ""); + if (full_name == NULL) { + torture_comment(tctx, "talloc_asprintf error\n"); + return false; + } + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_WRITE_DATA; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.fname = 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: %s\n", + full_name, nt_errstr(status)); + return false; + } + } + + handle = create.out.file.handle; + if (value == NULL) { + return true; + } + + status = smb2_util_write(tree, handle, value, offset, size); + + if (!NT_STATUS_IS_OK(status)) { + torture_comment(tctx, "(%s) Failed to write %lu bytes to " + "stream '%s'\n", location, (long)size, full_name); + 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 *xattr, + 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, xattr, 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 enable_aapl(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + NTSTATUS status; + bool ret = true; + struct smb2_create io; + DATA_BLOB data; + struct smb2_create_blob *aapl = NULL; + uint32_t aapl_server_caps; + uint32_t expected_scaps = (SMB2_CRTCTX_AAPL_UNIX_BASED | + SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR | + SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE | + SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE); + bool is_osx_server = torture_setting_bool(tctx, "osx", false); + + ZERO_STRUCT(io); + io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.share_access = (NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE); + io.in.fname = ""; + + /* + * Issuing an SMB2/CREATE with a suitably formed AAPL context, + * controls behaviour of Apple's SMB2 extensions for the whole + * session! + */ + + data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t)); + SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY); + SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS | + SMB2_CRTCTX_AAPL_VOLUME_CAPS | + SMB2_CRTCTX_AAPL_MODEL_INFO)); + SBVAL(data.data, 16, (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR | + SMB2_CRTCTX_AAPL_UNIX_BASED | + SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE)); + + status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_blob_add"); + + status = smb2_create(tree, tctx, &io); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + + status = smb2_util_close(tree, io.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close"); + + /* + * Now check returned AAPL context + */ + torture_comment(tctx, "Comparing returned AAPL capabilities\n"); + + aapl = smb2_create_blob_find(&io.out.blobs, + SMB2_CREATE_TAG_AAPL); + torture_assert_goto(tctx, aapl != NULL, ret, done, "missing AAPL context"); + + if (!is_osx_server) { + size_t expected_aapl_ctx_size; + + expected_aapl_ctx_size = strlen("MacSamba") * 2 + 40; + + torture_assert_goto( + tctx, aapl->data.length == expected_aapl_ctx_size, + ret, done, "bad AAPL size"); + } + + aapl_server_caps = BVAL(aapl->data.data, 16); + torture_assert_goto(tctx, aapl_server_caps == expected_scaps, + ret, done, "bad AAPL caps"); + +done: + talloc_free(mem_ctx); + return ret; +} + +static bool test_read_netatalk_metadata(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_read_metadata"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + ssize_t len; + const char *localdir = NULL; + + torture_comment(tctx, "Checking metadata access\n"); + + localdir = torture_setting_string(tctx, "localdir", NULL); + if (localdir == NULL) { + torture_skip(tctx, "Need localdir for test"); + } + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + ret = torture_setup_local_xattr(tctx, "localdir", + BASEDIR "/torture_read_metadata", + AFPINFO_EA_NETATALK, + metadata_xattr, sizeof(metadata_xattr)); + if (ret == false) { + goto done; + } + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 0, 4, "AFP"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, "BARRFOOO"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 16, 8, 0, 3, "AFP"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + /* Check reading offset and read size > sizeof(AFPINFO_STREAM) */ + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 0, 61); + CHECK_VALUE(len, 60); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 59, 2); + CHECK_VALUE(len, 2); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 60, 1); + CHECK_VALUE(len, 1); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 61, 1); + CHECK_VALUE(len, 0); + +done: + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_read_afpinfo(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_read_metadata"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + ssize_t len; + AfpInfo *info; + const char *type_creator = "SMB,OLE!"; + + torture_comment(tctx, "Checking metadata access\n"); + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 0, 4, "AFP"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + /* + * OS X ignores offset <= 60 and treats the as + * offset=0. Reading from offsets > 60 returns EOF=0. + */ + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 16, 8, 0, 8, "AFP\0\0\0\001\0"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 0, 61); + torture_assert_goto(tctx, len == 60, ret, done, "read_stream failed"); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 59, 2); + torture_assert_goto(tctx, len == 2, ret, done, "read_stream failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 59, 2, 0, 2, "AF"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 60, 1); + torture_assert_goto(tctx, len == 1, ret, done, "read_stream failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 60, 1, 0, 1, "A"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + + len = read_stream(tree, __location__, tctx, mem_ctx, fname, + AFPINFO_STREAM, 61, 1); + torture_assert_goto(tctx, len == 0, ret, done, "read_stream failed"); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_write_atalk_metadata(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_write_metadata"; + const char *type_creator = "SMB,OLE!"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + AfpInfo *info; + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + info = torture_afpinfo_new(mem_ctx); + if (info == NULL) { + goto done; + } + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + ret &= check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_write_atalk_rfork_io(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_write_rfork_io"; + const char *rfork = BASEDIR "\\torture_write_rfork_io" AFPRESOURCE_STREAM_NAME; + const char *rfork_content = "1234567890"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + + union smb_open io; + struct smb2_handle filehandle; + union smb_fileinfo finfo; + union smb_setfileinfo sinfo; + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + torture_comment(tctx, "(%s) writing to resource fork\n", + __location__); + + ret &= write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 10, 10, rfork_content); + + ret &= check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 20, 10, 10, rfork_content); + + /* Check size after write */ + + ZERO_STRUCT(io); + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; + io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE | + SEC_FILE_WRITE_ATTRIBUTE; + io.smb2.in.fname = rfork; + status = smb2_create(tree, mem_ctx, &(io.smb2)); + CHECK_STATUS(status, NT_STATUS_OK); + filehandle = io.smb2.out.file.handle; + + torture_comment(tctx, "(%s) check resource fork size after write\n", + __location__); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION; + finfo.generic.in.file.handle = filehandle; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + CHECK_STATUS(status, NT_STATUS_OK); + if (finfo.all_info.out.size != 20) { + torture_result(tctx, TORTURE_FAIL, + "(%s) Incorrect resource fork size\n", + __location__); + ret = false; + smb2_util_close(tree, filehandle); + goto done; + } + smb2_util_close(tree, filehandle); + + /* Write at large offset */ + + torture_comment(tctx, "(%s) writing to resource fork at large offset\n", + __location__); + + ret &= write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + (off_t)64*1024*1024, 10, rfork_content); + + /* Check size after write */ + + ZERO_STRUCT(io); + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; + io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE | + SEC_FILE_WRITE_ATTRIBUTE; + io.smb2.in.fname = rfork; + status = smb2_create(tree, mem_ctx, &(io.smb2)); + CHECK_STATUS(status, NT_STATUS_OK); + filehandle = io.smb2.out.file.handle; + + torture_comment(tctx, "(%s) check resource fork size after write\n", + __location__); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION; + finfo.generic.in.file.handle = filehandle; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + CHECK_STATUS(status, NT_STATUS_OK); + if (finfo.all_info.out.size != 64*1024*1024 + 10) { + torture_result(tctx, TORTURE_FAIL, + "(%s) Incorrect resource fork size\n", + __location__); + ret = false; + smb2_util_close(tree, filehandle); + goto done; + } + smb2_util_close(tree, filehandle); + + ret &= check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + (off_t)64*1024*1024, 10, 0, 10, rfork_content); + + /* Truncate back to size of 1 byte */ + + torture_comment(tctx, "(%s) truncate resource fork and check size\n", + __location__); + + ZERO_STRUCT(io); + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; + io.smb2.in.desired_access = SEC_FILE_ALL; + io.smb2.in.fname = rfork; + status = smb2_create(tree, mem_ctx, &(io.smb2)); + CHECK_STATUS(status, NT_STATUS_OK); + filehandle = io.smb2.out.file.handle; + + ZERO_STRUCT(sinfo); + sinfo.end_of_file_info.level = + RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sinfo.end_of_file_info.in.file.handle = filehandle; + sinfo.end_of_file_info.in.size = 1; + status = smb2_setinfo_file(tree, &sinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + smb2_util_close(tree, filehandle); + + /* Now check size */ + ZERO_STRUCT(io); + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; + io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE | + SEC_FILE_WRITE_ATTRIBUTE; + io.smb2.in.fname = rfork; + status = smb2_create(tree, mem_ctx, &(io.smb2)); + CHECK_STATUS(status, NT_STATUS_OK); + filehandle = io.smb2.out.file.handle; + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION; + finfo.generic.in.file.handle = filehandle; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + CHECK_STATUS(status, NT_STATUS_OK); + if (finfo.all_info.out.size != 1) { + torture_result(tctx, TORTURE_FAIL, + "(%s) Incorrect resource fork size\n", + __location__); + ret = false; + smb2_util_close(tree, filehandle); + goto done; + } + smb2_util_close(tree, filehandle); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_rfork_truncate(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_rfork_truncate"; + const char *rfork = BASEDIR "\\torture_rfork_truncate" AFPRESOURCE_STREAM; + const char *rfork_content = "1234567890"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create create; + struct smb2_handle fh1, fh2, fh3; + union smb_setfileinfo sinfo; + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + ret &= write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM, + 10, 10, rfork_content); + + /* Truncate back to size 0, further access MUST return ENOENT */ + + torture_comment(tctx, "(%s) truncate resource fork to size 0\n", + __location__); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = fname; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + fh1 = create.out.file.handle; + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + fh2 = create.out.file.handle; + + ZERO_STRUCT(sinfo); + sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sinfo.end_of_file_info.in.file.handle = fh2; + sinfo.end_of_file_info.in.size = 0; + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file"); + + /* + * Now check size, we should get OBJECT_NAME_NOT_FOUND (!) + */ + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create"); + + /* + * Do another open on the rfork and write to the new handle. A + * naive server might unlink the AppleDouble resource fork + * file when its truncated to 0 bytes above, so in case both + * open handles share the same underlying fd, the unlink would + * cause the below write to be lost. + */ + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + fh3 = create.out.file.handle; + + status = smb2_util_write(tree, fh3, "foo", 0, 3); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write"); + + smb2_util_close(tree, fh3); + smb2_util_close(tree, fh2); + smb2_util_close(tree, fh1); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM, + 0, 3, 0, 3, "foo"); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream"); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_rfork_create(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_rfork_create"; + const char *rfork = BASEDIR "\\torture_rfork_create" AFPRESOURCE_STREAM; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create create; + struct smb2_handle fh1; + const char *streams[] = { + "::$DATA" + }; + union smb_fileinfo finfo; + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + torture_comment(tctx, "(%s) open rfork, should return ENOENT\n", + __location__); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create"); + + torture_comment(tctx, "(%s) create resource fork\n", __location__); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + fh1 = create.out.file.handle; + + torture_comment(tctx, "(%s) getinfo on create handle\n", + __location__); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION; + finfo.generic.in.file.handle = fh1; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file"); + if (finfo.all_info.out.size != 0) { + torture_result(tctx, TORTURE_FAIL, + "(%s) Incorrect resource fork size\n", + __location__); + ret = false; + smb2_util_close(tree, fh1); + goto done; + } + + torture_comment(tctx, "(%s) open rfork, should still return ENOENT\n", + __location__); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create"); + + ret = check_stream_list(tree, tctx, fname, 1, streams, false); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list"); + + torture_comment(tctx, "(%s) close empty created rfork, open should return ENOENT\n", + __location__); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create"); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +/* + * BUG: https://bugzilla.samba.org/show_bug.cgi?id=15182 + */ + +static bool test_rfork_fsync(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_rfork_fsync"; + const char *rfork = BASEDIR "\\torture_rfork_fsync" AFPRESOURCE_STREAM; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create create; + struct smb2_handle fh1; + struct smb2_flush f; + + ZERO_STRUCT(fh1); + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + smb2_util_unlink(tree, fname); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, + status, + ret, + done, + "torture_smb2_testdir"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + torture_comment(tctx, "(%s) create resource fork %s\n", + __location__, + rfork); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.fname = rfork; + create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE | + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + fh1 = create.out.file.handle; + + torture_comment(tctx, "(%s) Write 10 bytes to resource fork %s\n", + __location__, + rfork); + + status = smb2_util_write(tree, fh1, "1234567890", 0, 10); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + torture_comment(tctx, "(%s) fsync on resource fork %s\n", + __location__, + rfork); + + f.in.file.handle = fh1; + status = smb2_flush(tree, &f); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_flush failed\n"); + +done: + + smb2_util_close(tree, fh1); + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_rfork_create_ro(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_rfork_create"; + const char *rfork = BASEDIR "\\torture_rfork_create" AFPRESOURCE_STREAM; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create create; + + smb2_util_unlink(tree, fname); + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + goto done; + } + + torture_comment(tctx, "(%s) Try opening read-only with " + "open_if create disposition, should work\n", + __location__); + + ZERO_STRUCT(create); + create.in.fname = rfork; + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.desired_access = SEC_FILE_READ_DATA | SEC_STD_READ_CONTROL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.share_access = FILE_SHARE_READ | FILE_SHARE_DELETE; + status = smb2_create(tree, mem_ctx, &(create)); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + smb2_util_close(tree, create.out.file.handle); + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_adouble_conversion(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\test_adouble_conversion"; + const char *adname = BASEDIR "/._test_adouble_conversion"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + const char data[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + size_t datalen = sizeof(data); + const char *streams[] = { + "::$DATA", + AFPINFO_STREAM, + AFPRESOURCE_STREAM, + ":com.apple.metadata" "\xef\x80\xa2" "_kMDItemUserTags:$DATA", + ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */ + }; + bool is_osx = torture_setting_bool(tctx, "osx", false); + + if (is_osx) { + torture_skip(tctx, "Test only works with Samba\n"); + } + + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = torture_setup_file(tctx, tree, adname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + adname, NULL, + 0, + sizeof(osx_adouble_non_empty_rfork_w_xattr), + osx_adouble_non_empty_rfork_w_xattr); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + torture_comment(tctx, "(%s) test OS X AppleDouble conversion\n", + __location__); + + ret = check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM, + 16, datalen, 0, datalen, data); + torture_assert_goto(tctx, ret == true, ret, done, + "check AFPRESOURCE_STREAM failed\n"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPINFO_STREAM, + 0, 60, 16, 8, "TESTSLOW"); + torture_assert_goto(tctx, ret == true, ret, done, + "check AFPINFO_STREAM failed\n"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, + ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */ + 0, 3, 0, 3, "baz"); + torture_assert_goto(tctx, ret == true, ret, done, + "check foo:bar stream failed\n"); + + ret = check_stream_list(tree, tctx, fname, 5, streams, false); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list"); + +done: + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +/* + * Test conversion of AppleDouble file without embedded xattr data + */ +static bool test_adouble_conversion_wo_xattr(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\test_adouble_conversion"; + const char *adname = BASEDIR "/._test_adouble_conversion"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + const char *streams[] = { + "::$DATA", + AFPINFO_STREAM, + AFPRESOURCE_STREAM + }; + struct smb2_create create; + struct smb2_find find; + unsigned int count; + union smb_search_data *d; + const char data[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + size_t datalen = sizeof(data); + bool is_osx = torture_setting_bool(tctx, "osx", false); + + if (is_osx) { + torture_skip(tctx, "Test only works with Samba\n"); + } + + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + smb2_util_close(tree, testdirh); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = torture_setup_file(tctx, tree, adname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + adname, NULL, 0, + sizeof(osx_adouble_without_xattr), + osx_adouble_without_xattr); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + /* + * Issue a smb2_find(), this triggers the server-side conversion + */ + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_DIR_READ, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = BASEDIR, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + find = (struct smb2_find) { + .in.file.handle = create.out.file.handle, + .in.pattern = "*", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + }; + + status = smb2_find_level(tree, tree, &find, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + status = smb2_util_close(tree, create.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed"); + + /* + * Check number of streams + */ + + ret = check_stream_list(tree, tctx, fname, 3, streams, false); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list"); + + + /* + * Check Resourcefork data can be read. + */ + + ret = check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM, + 16, datalen, 0, datalen, data); + torture_assert_goto(tctx, ret == true, ret, done, + "check AFPRESOURCE_STREAM failed\n"); + + /* + * Check FinderInfo data has been migrated to stream. + */ + + ret = check_stream(tree, __location__, tctx, mem_ctx, + fname, AFPINFO_STREAM, + 0, 60, 16, 8, "WAVEPTul"); + torture_assert_goto(tctx, ret == true, ret, done, + "check AFPINFO_STREAM failed\n"); + +done: + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_aapl(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\test_aapl"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create io; + DATA_BLOB data; + struct smb2_create_blob *aapl = NULL; + AfpInfo *info; + const char *type_creator = "SMB,OLE!"; + char type_creator_buf[9]; + uint32_t aapl_cmd; + uint32_t aapl_reply_bitmap; + uint32_t aapl_server_caps; + uint32_t aapl_vol_caps; + uint32_t expected_vol_caps = 0; + char *model; + struct smb2_find f; + unsigned int count; + union smb_search_data *d; + uint64_t rfork_len; + bool is_osx_server = torture_setting_bool(tctx, "osx", false); + + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, testdirh); + + 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.fname = fname; + + /* + * Issuing an SMB2/CREATE with a suitably formed AAPL context, + * controls behaviour of Apple's SMB2 extensions for the whole + * session! + */ + + data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t)); + SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY); + SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS | + SMB2_CRTCTX_AAPL_VOLUME_CAPS | + SMB2_CRTCTX_AAPL_MODEL_INFO)); + SBVAL(data.data, 16, (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR | + SMB2_CRTCTX_AAPL_UNIX_BASED | + SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE)); + + torture_comment(tctx, "Testing SMB2 create context AAPL\n"); + status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + status = smb2_util_close(tree, io.out.file.handle); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * Now check returned AAPL context + */ + torture_comment(tctx, "Comparing returned AAPL capabilities\n"); + + aapl = smb2_create_blob_find(&io.out.blobs, + SMB2_CREATE_TAG_AAPL); + + if (aapl == NULL) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpectedly no AAPL capabilities were returned.", + __location__); + ret = false; + goto done; + } + + if (!is_osx_server) { + size_t expected_aapl_ctx_size; + bool size_ok; + + /* + * uint32_t CommandCode = kAAPL_SERVER_QUERY + * uint32_t Reserved = 0; + * uint64_t ReplyBitmap = kAAPL_SERVER_CAPS | + * kAAPL_VOLUME_CAPS | + * kAAPL_MODEL_INFO; + * uint64_t ServerCaps = kAAPL_SUPPORTS_READDIR_ATTR | + * kAAPL_SUPPORTS_OSX_COPYFILE; + * uint64_t VolumeCaps = kAAPL_SUPPORT_RESOLVE_ID | + * kAAPL_CASE_SENSITIVE; + * uint32_t Pad2 = 0; + * uint32_t ModelStringLen = 10; + * ucs2_t ModelString[5] = "MacSamba"; + */ + expected_aapl_ctx_size = strlen("MacSamba") * 2 + 40; + + size_ok = aapl->data.length == expected_aapl_ctx_size; + torture_assert_goto(tctx, size_ok, ret, done, "bad AAPL size"); + } + + aapl_cmd = IVAL(aapl->data.data, 0); + if (aapl_cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected cmd: %d", + __location__, (int)aapl_cmd); + ret = false; + goto done; + } + + aapl_reply_bitmap = BVAL(aapl->data.data, 8); + if (aapl_reply_bitmap != (SMB2_CRTCTX_AAPL_SERVER_CAPS | + SMB2_CRTCTX_AAPL_VOLUME_CAPS | + SMB2_CRTCTX_AAPL_MODEL_INFO)) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected reply_bitmap: %d", + __location__, (int)aapl_reply_bitmap); + ret = false; + goto done; + } + + aapl_server_caps = BVAL(aapl->data.data, 16); + if (aapl_server_caps != (SMB2_CRTCTX_AAPL_UNIX_BASED | + SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR | + SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE | + SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE)) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected server_caps: %d", + __location__, (int)aapl_server_caps); + ret = false; + goto done; + } + + if (is_osx_server) { + expected_vol_caps = 5; + } + aapl_vol_caps = BVAL(aapl->data.data, 24); + if (aapl_vol_caps != expected_vol_caps) { + /* this will fail on a case insensitive fs ... */ + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected vol_caps: %d", + __location__, (int)aapl_vol_caps); + } + + ret = convert_string_talloc(mem_ctx, + CH_UTF16LE, CH_UNIX, + aapl->data.data + 40, 10, + &model, NULL); + if (ret == false) { + torture_result(tctx, TORTURE_FAIL, + "(%s) convert_string_talloc() failed", + __location__); + goto done; + } + torture_comment(tctx, "Got server model: \"%s\"\n", model); + + /* + * Now that Requested AAPL extensions are enabled, setup some + * Mac files with metadata and resource fork + */ + ret = torture_setup_file(mem_ctx, tree, fname, false); + if (ret == false) { + torture_result(tctx, TORTURE_FAIL, + "(%s) torture_setup_file() failed", + __location__); + goto done; + } + + info = torture_afpinfo_new(mem_ctx); + if (info == NULL) { + torture_result(tctx, TORTURE_FAIL, + "(%s) torture_afpinfo_new() failed", + __location__); + ret = false; + goto done; + } + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + if (ret == false) { + torture_result(tctx, TORTURE_FAIL, + "(%s) torture_write_afpinfo() failed", + __location__); + goto done; + } + + ret = write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 3, "foo"); + if (ret == false) { + torture_result(tctx, TORTURE_FAIL, + "(%s) write_stream() failed", + __location__); + goto done; + } + + /* + * Ok, file is prepared, now call smb2/find + */ + + ZERO_STRUCT(io); + io.in.desired_access = SEC_RIGHTS_DIR_READ; + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE); + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.fname = BASEDIR; + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(f); + f.in.file.handle = io.out.file.handle; + f.in.pattern = "test_aapl"; + f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE; + f.in.max_response_size = 0x1000; + f.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO; + + status = smb2_find_level(tree, tree, &f, &count, &d); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_util_close(tree, io.out.file.handle); + CHECK_STATUS(status, NT_STATUS_OK); + + if (strcmp(d[0].id_both_directory_info.name.s, "test_aapl") != 0) { + torture_result(tctx, TORTURE_FAIL, + "(%s) write_stream() failed", + __location__); + ret = false; + goto done; + } + + if (d[0].id_both_directory_info.short_name.private_length != 24) { + torture_result(tctx, TORTURE_FAIL, + "(%s) bad short_name length %" PRIu32 ", expected 24", + __location__, d[0].id_both_directory_info.short_name.private_length); + ret = false; + goto done; + } + + torture_comment(tctx, "short_name buffer:\n"); + dump_data(0, d[0].id_both_directory_info.short_name_buf, 24); + + /* + * Extract data as specified by the AAPL extension: + * - ea_size contains max_access + * - short_name contains resource fork length + FinderInfo + * - reserved2 contains the unix mode + */ + torture_comment(tctx, "mac_access: %" PRIx32 "\n", + d[0].id_both_directory_info.ea_size); + + rfork_len = BVAL(d[0].id_both_directory_info.short_name_buf, 0); + if (rfork_len != 3) { + torture_result(tctx, TORTURE_FAIL, + "(%s) expected resource fork length 3, got: %" PRIu64, + __location__, rfork_len); + ret = false; + goto done; + } + + memcpy(type_creator_buf, d[0].id_both_directory_info.short_name_buf + 8, 8); + type_creator_buf[8] = 0; + if (strcmp(type_creator, type_creator_buf) != 0) { + torture_result(tctx, TORTURE_FAIL, + "(%s) expected type/creator \"%s\" , got: %s", + __location__, type_creator, type_creator_buf); + ret = false; + goto done; + } + +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static uint64_t patt_hash(uint64_t off) +{ + return off; +} + +static bool write_pattern(struct torture_context *torture, + struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + struct smb2_handle h, uint64_t off, uint64_t len, + uint64_t patt_off) +{ + NTSTATUS status; + uint64_t i; + uint8_t *buf; + uint64_t io_sz = MIN(1024 * 64, len); + + if (len == 0) { + return true; + } + + torture_assert(torture, (len % 8) == 0, "invalid write len"); + + buf = talloc_zero_size(mem_ctx, io_sz); + torture_assert(torture, (buf != NULL), "no memory for file data buf"); + + while (len > 0) { + for (i = 0; i <= io_sz - 8; i += 8) { + SBVAL(buf, i, patt_hash(patt_off)); + patt_off += 8; + } + + status = smb2_util_write(tree, h, + buf, off, io_sz); + torture_assert_ntstatus_ok(torture, status, "file write"); + + len -= io_sz; + off += io_sz; + } + + talloc_free(buf); + + return true; +} + +static bool check_pattern(struct torture_context *torture, + struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + struct smb2_handle h, uint64_t off, uint64_t len, + uint64_t patt_off) +{ + if (len == 0) { + return true; + } + + torture_assert(torture, (len % 8) == 0, "invalid read len"); + + while (len > 0) { + uint64_t i; + struct smb2_read r; + NTSTATUS status; + uint64_t io_sz = MIN(1024 * 64, len); + + ZERO_STRUCT(r); + r.in.file.handle = h; + r.in.length = io_sz; + r.in.offset = off; + status = smb2_read(tree, mem_ctx, &r); + torture_assert_ntstatus_ok(torture, status, "read"); + + torture_assert_u64_equal(torture, r.out.data.length, io_sz, + "read data len mismatch"); + + for (i = 0; i <= io_sz - 8; i += 8, patt_off += 8) { + uint64_t data = BVAL(r.out.data.data, i); + torture_assert_u64_equal(torture, data, patt_hash(patt_off), + talloc_asprintf(torture, "read data " + "pattern bad at %llu\n", + (unsigned long long)off + i)); + } + talloc_free(r.out.data.data); + len -= io_sz; + off += io_sz; + } + + return true; +} + +static bool test_setup_open(struct torture_context *torture, + struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + const char *fname, + struct smb2_handle *fh, + uint32_t desired_access, + uint32_t file_attributes) +{ + struct smb2_create io; + NTSTATUS status; + + ZERO_STRUCT(io); + io.in.desired_access = desired_access; + io.in.file_attributes = file_attributes; + io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + if (file_attributes & FILE_ATTRIBUTE_DIRECTORY) { + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + } + io.in.fname = fname; + + status = smb2_create(tree, mem_ctx, &io); + torture_assert_ntstatus_ok(torture, status, "file create"); + + *fh = io.out.file.handle; + + return true; +} + +static bool test_setup_create_fill(struct torture_context *torture, + struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + const char *fname, + struct smb2_handle *fh, + uint64_t size, + uint32_t desired_access, + uint32_t file_attributes) +{ + bool ok; + + ok = test_setup_open(torture, tree, mem_ctx, + fname, + fh, + desired_access, + file_attributes); + torture_assert(torture, ok, "file open"); + + if (size > 0) { + ok = write_pattern(torture, tree, mem_ctx, *fh, 0, size, 0); + torture_assert(torture, ok, "write pattern"); + } + return true; +} + +static bool test_setup_copy_chunk(struct torture_context *torture, + struct smb2_tree *tree, TALLOC_CTX *mem_ctx, + uint32_t nchunks, + const char *src_name, + struct smb2_handle *src_h, + uint64_t src_size, + uint32_t src_desired_access, + const char *dst_name, + struct smb2_handle *dest_h, + uint64_t dest_size, + uint32_t dest_desired_access, + struct srv_copychunk_copy *cc_copy, + union smb_ioctl *io) +{ + struct req_resume_key_rsp res_key; + bool ok; + NTSTATUS status; + enum ndr_err_code ndr_ret; + + ok = test_setup_create_fill(torture, tree, mem_ctx, src_name, + src_h, src_size, src_desired_access, + FILE_ATTRIBUTE_NORMAL); + torture_assert(torture, ok, "src file create fill"); + + ok = test_setup_create_fill(torture, tree, mem_ctx, dst_name, + dest_h, dest_size, dest_desired_access, + FILE_ATTRIBUTE_NORMAL); + torture_assert(torture, ok, "dest file create fill"); + + ZERO_STRUCTPN(io); + io->smb2.level = RAW_IOCTL_SMB2; + io->smb2.in.file.handle = *src_h; + io->smb2.in.function = FSCTL_SRV_REQUEST_RESUME_KEY; + /* Allow for Key + ContextLength + Context */ + io->smb2.in.max_output_response = 32; + io->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; + + status = smb2_ioctl(tree, mem_ctx, &io->smb2); + torture_assert_ntstatus_ok(torture, status, + "FSCTL_SRV_REQUEST_RESUME_KEY"); + + ndr_ret = ndr_pull_struct_blob(&io->smb2.out.out, mem_ctx, &res_key, + (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp); + + torture_assert_ndr_success(torture, ndr_ret, + "ndr_pull_req_resume_key_rsp"); + + ZERO_STRUCTPN(io); + io->smb2.level = RAW_IOCTL_SMB2; + io->smb2.in.file.handle = *dest_h; + io->smb2.in.function = FSCTL_SRV_COPYCHUNK; + io->smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp); + io->smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL; + + ZERO_STRUCTPN(cc_copy); + memcpy(cc_copy->source_key, res_key.resume_key, ARRAY_SIZE(cc_copy->source_key)); + cc_copy->chunk_count = nchunks; + cc_copy->chunks = talloc_zero_array(mem_ctx, struct srv_copychunk, nchunks); + torture_assert(torture, (cc_copy->chunks != NULL), "no memory for chunks"); + + return true; +} + + +static bool check_copy_chunk_rsp(struct torture_context *torture, + struct srv_copychunk_rsp *cc_rsp, + uint32_t ex_chunks_written, + uint32_t ex_chunk_bytes_written, + uint32_t ex_total_bytes_written) +{ + torture_assert_int_equal(torture, cc_rsp->chunks_written, + ex_chunks_written, "num chunks"); + torture_assert_int_equal(torture, cc_rsp->chunk_bytes_written, + ex_chunk_bytes_written, "chunk bytes written"); + torture_assert_int_equal(torture, cc_rsp->total_bytes_written, + ex_total_bytes_written, "chunk total bytes"); + return true; +} + +static bool neg_aapl_copyfile(struct torture_context *tctx, + struct smb2_tree *tree, + uint64_t flags) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = "aapl"; + NTSTATUS status; + struct smb2_create io; + DATA_BLOB data; + struct smb2_create_blob *aapl = NULL; + uint32_t aapl_cmd; + uint32_t aapl_reply_bitmap; + uint32_t aapl_server_caps; + bool ret = true; + + 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.fname = fname; + + data = data_blob_talloc(mem_ctx, NULL, 3 * sizeof(uint64_t)); + SBVAL(data.data, 0, SMB2_CRTCTX_AAPL_SERVER_QUERY); + SBVAL(data.data, 8, (SMB2_CRTCTX_AAPL_SERVER_CAPS)); + SBVAL(data.data, 16, flags); + + status = smb2_create_blob_add(tctx, &io.in.blobs, "AAPL", data); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + aapl = smb2_create_blob_find(&io.out.blobs, + SMB2_CREATE_TAG_AAPL); + if (aapl == NULL) { + ret = false; + goto done; + + } + if (aapl->data.length < 24) { + ret = false; + goto done; + } + + aapl_cmd = IVAL(aapl->data.data, 0); + if (aapl_cmd != SMB2_CRTCTX_AAPL_SERVER_QUERY) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected cmd: %d", + __location__, (int)aapl_cmd); + ret = false; + goto done; + } + + aapl_reply_bitmap = BVAL(aapl->data.data, 8); + if (!(aapl_reply_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS)) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected reply_bitmap: %d", + __location__, (int)aapl_reply_bitmap); + ret = false; + goto done; + } + + aapl_server_caps = BVAL(aapl->data.data, 16); + if (!(aapl_server_caps & flags)) { + torture_result(tctx, TORTURE_FAIL, + "(%s) unexpected server_caps: %d", + __location__, (int)aapl_server_caps); + ret = false; + goto done; + } + +done: + status = smb2_util_close(tree, io.out.file.handle); + CHECK_STATUS(status, NT_STATUS_OK); + + smb2_util_unlink(tree, "aapl"); + talloc_free(mem_ctx); + return ret; +} + +static bool test_copyfile(struct torture_context *torture, + struct smb2_tree *tree) +{ + struct smb2_handle src_h; + struct smb2_handle dest_h; + NTSTATUS status; + union smb_ioctl io; + TALLOC_CTX *tmp_ctx = talloc_new(tree); + struct srv_copychunk_copy cc_copy; + struct srv_copychunk_rsp cc_rsp; + enum ndr_err_code ndr_ret; + bool ok; + const char *sname = ":foo" "\xef\x80\xa2" "bar:$DATA"; + + /* + * First test a copy_chunk with a 0 chunk count without having + * enabled this via AAPL. The request must not fail and the + * copied length in the response must be 0. This is verified + * against Windows 2008r2. + */ + + ok = test_setup_copy_chunk(torture, tree, tmp_ctx, + 0, /* 0 chunks, copyfile semantics */ + FNAME_CC_SRC, + &src_h, 4096, /* fill 4096 byte src file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + FNAME_CC_DST, + &dest_h, 0, /* 0 byte dest file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + &cc_copy, + &io); + if (!ok) { + torture_fail_goto(torture, done, "setup copy chunk error"); + } + + ndr_ret = ndr_push_struct_blob(&io.smb2.in.out, tmp_ctx, + &cc_copy, + (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy); + torture_assert_ndr_success(torture, ndr_ret, + "ndr_push_srv_copychunk_copy"); + + status = smb2_ioctl(tree, tmp_ctx, &io.smb2); + torture_assert_ntstatus_ok_goto(torture, status, ok, done, "FSCTL_SRV_COPYCHUNK"); + + ndr_ret = ndr_pull_struct_blob(&io.smb2.out.out, tmp_ctx, + &cc_rsp, + (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp); + torture_assert_ndr_success(torture, ndr_ret, + "ndr_pull_srv_copychunk_rsp"); + + ok = check_copy_chunk_rsp(torture, &cc_rsp, + 0, /* chunks written */ + 0, /* chunk bytes unsuccessfully written */ + 0); /* total bytes written */ + if (!ok) { + torture_fail_goto(torture, done, "bad copy chunk response data"); + } + + /* + * Now enable AAPL copyfile and test again, the file and the + * stream must be copied by the server. + */ + ok = neg_aapl_copyfile(torture, tree, + SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE); + if (!ok) { + torture_skip_goto(torture, done, "missing AAPL copyfile"); + goto done; + } + + smb2_util_close(tree, src_h); + smb2_util_close(tree, dest_h); + smb2_util_unlink(tree, FNAME_CC_SRC); + smb2_util_unlink(tree, FNAME_CC_DST); + + ok = torture_setup_file(tmp_ctx, tree, FNAME_CC_SRC, false); + if (!ok) { + torture_fail(torture, "setup file error"); + } + ok = write_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_SRC, AFPRESOURCE_STREAM, + 10, 10, "1234567890"); + if (!ok) { + torture_fail(torture, "setup stream error"); + } + + ok = write_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_SRC, sname, + 10, 10, "abcdefghij"); + torture_assert_goto(torture, ok == true, ok, done, "write_stream failed\n"); + + ok = test_setup_copy_chunk(torture, tree, tmp_ctx, + 0, /* 0 chunks, copyfile semantics */ + FNAME_CC_SRC, + &src_h, 4096, /* fill 4096 byte src file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + FNAME_CC_DST, + &dest_h, 0, /* 0 byte dest file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + &cc_copy, + &io); + if (!ok) { + torture_fail_goto(torture, done, "setup copy chunk error"); + } + + ndr_ret = ndr_push_struct_blob(&io.smb2.in.out, tmp_ctx, + &cc_copy, + (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy); + torture_assert_ndr_success(torture, ndr_ret, + "ndr_push_srv_copychunk_copy"); + + status = smb2_ioctl(tree, tmp_ctx, &io.smb2); + torture_assert_ntstatus_ok_goto(torture, status, ok, done, "FSCTL_SRV_COPYCHUNK"); + + ndr_ret = ndr_pull_struct_blob(&io.smb2.out.out, tmp_ctx, + &cc_rsp, + (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp); + torture_assert_ndr_success(torture, ndr_ret, + "ndr_pull_srv_copychunk_rsp"); + + ok = check_copy_chunk_rsp(torture, &cc_rsp, + 0, /* chunks written */ + 0, /* chunk bytes unsuccessfully written */ + 4096); /* total bytes written */ + if (!ok) { + torture_fail_goto(torture, done, "bad copy chunk response data"); + } + + ok = test_setup_open(torture, tree, tmp_ctx, FNAME_CC_DST, &dest_h, + SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL); + if (!ok) { + torture_fail_goto(torture, done,"open failed"); + } + ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 4096, 0); + if (!ok) { + torture_fail_goto(torture, done, "inconsistent file data"); + } + + ok = check_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_DST, AFPRESOURCE_STREAM, + 0, 20, 10, 10, "1234567890"); + if (!ok) { + torture_fail_goto(torture, done, "inconsistent stream data"); + } + + ok = check_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_DST, sname, + 0, 20, 10, 10, "abcdefghij"); + torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n"); + +done: + smb2_util_close(tree, src_h); + smb2_util_close(tree, dest_h); + smb2_util_unlink(tree, FNAME_CC_SRC); + smb2_util_unlink(tree, FNAME_CC_DST); + talloc_free(tmp_ctx); + return true; +} + +static bool check_stream_list(struct smb2_tree *tree, + struct torture_context *tctx, + const char *fname, + int num_exp, + const char **exp, + bool is_dir) +{ + bool ret = true; + union smb_fileinfo finfo; + NTSTATUS status; + int i; + TALLOC_CTX *tmp_ctx = talloc_new(tctx); + char **exp_sort; + struct stream_struct *stream_sort; + struct smb2_create create; + struct smb2_handle h; + + ZERO_STRUCT(h); + torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, "talloc_new failed"); + + ZERO_STRUCT(create); + create.in.fname = fname; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.create_options = is_dir ? NTCREATEX_OPTIONS_DIRECTORY : 0; + create.in.file_attributes = is_dir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + status = smb2_create(tree, tmp_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create"); + h = create.out.file.handle; + + finfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION; + finfo.generic.in.file.handle = h; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "get stream info"); + + smb2_util_close(tree, h); + + torture_assert_int_equal_goto(tctx, finfo.stream_info.out.num_streams, num_exp, + ret, done, "stream count"); + + if (num_exp == 0) { + TALLOC_FREE(tmp_ctx); + goto done; + } + + exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp)); + torture_assert_goto(tctx, exp_sort != NULL, ret, done, __location__); + + TYPESAFE_QSORT(exp_sort, num_exp, qsort_string); + + stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams, + finfo.stream_info.out.num_streams * + sizeof(*stream_sort)); + torture_assert_goto(tctx, stream_sort != NULL, ret, done, __location__); + + TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream); + + for (i=0; i<num_exp; i++) { + torture_comment(tctx, "i[%d] exp[%s] got[%s]\n", + i, exp_sort[i], stream_sort[i].stream_name.s); + torture_assert_str_equal_goto(tctx, stream_sort[i].stream_name.s, exp_sort[i], + ret, done, "stream name"); + } + +done: + TALLOC_FREE(tmp_ctx); + return ret; +} + +static bool check_stream_list_handle(struct smb2_tree *tree, + struct torture_context *tctx, + struct smb2_handle h, + int num_exp, + const char **exp, + bool is_dir) +{ + bool ret = true; + union smb_fileinfo finfo; + NTSTATUS status; + int i; + TALLOC_CTX *tmp_ctx = talloc_new(tctx); + char **exp_sort; + struct stream_struct *stream_sort; + + torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, + "talloc_new failed\n"); + + finfo = (union smb_fileinfo) { + .stream_info.level = RAW_FILEINFO_STREAM_INFORMATION, + .stream_info.in.file.handle = h, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "get stream info\n"); + + torture_assert_int_equal_goto(tctx, finfo.stream_info.out.num_streams, + num_exp, ret, done, "stream count\n"); + + if (num_exp == 0) { + TALLOC_FREE(tmp_ctx); + goto done; + } + + exp_sort = talloc_memdup(tmp_ctx, exp, num_exp * sizeof(*exp)); + torture_assert_goto(tctx, exp_sort != NULL, ret, done, __location__); + + TYPESAFE_QSORT(exp_sort, num_exp, qsort_string); + + stream_sort = talloc_memdup(tmp_ctx, finfo.stream_info.out.streams, + finfo.stream_info.out.num_streams * + sizeof(*stream_sort)); + torture_assert_goto(tctx, stream_sort != NULL, ret, done, __location__); + + TYPESAFE_QSORT(stream_sort, finfo.stream_info.out.num_streams, qsort_stream); + + for (i=0; i<num_exp; i++) { + torture_comment(tctx, "i[%d] exp[%s] got[%s]\n", + i, exp_sort[i], stream_sort[i].stream_name.s); + torture_assert_str_equal_goto(tctx, stream_sort[i].stream_name.s, + exp_sort[i], ret, done, + "stream name\n"); + } + +done: + TALLOC_FREE(tmp_ctx); + return ret; +} + +/* + test stream names +*/ +static bool test_stream_names(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h; + const char *fname = BASEDIR "\\stream_names.txt"; + const char *sname1; + bool ret; + /* UTF8 private use are starts at 0xef 0x80 0x80 (0xf000) */ + const char *streams[] = { + ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */ + "::$DATA" + }; + + sname1 = talloc_asprintf(mem_ctx, "%s%s", fname, streams[0]); + + /* clean slate ...*/ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret, ret, done, "torture_setup_file"); + + torture_comment(tctx, "(%s) testing stream names\n", __location__); + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_WRITE_DATA; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create.in.create_disposition = NTCREATEX_DISP_CREATE; + create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + create.in.fname = sname1; + + status = smb2_create(tree, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_util_write(tree, create.out.file.handle, "foo", 0, 3); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + smb2_util_close(tree, create.out.file.handle); + + ret = check_stream_list(tree, tctx, fname, 2, streams, false); + CHECK_VALUE(ret, true); + +done: + status = smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + + return ret; +} + +/* Renaming a directory with open file, should work for OS X AAPL clients */ +static bool test_rename_dir_openfile(struct torture_context *torture, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + union smb_open io; + union smb_close cl; + union smb_setfileinfo sinfo; + struct smb2_handle d1, h1; + const char *renamedir = BASEDIR "-new"; + bool server_is_osx = torture_setting_bool(torture, "osx", false); + + smb2_deltree(tree, BASEDIR); + smb2_util_rmdir(tree, BASEDIR); + smb2_deltree(tree, renamedir); + + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.create_flags = 0; + io.smb2.in.desired_access = 0x0017019f; + io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.smb2.in.share_access = 0; + io.smb2.in.alloc_size = 0; + io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = BASEDIR; + + status = smb2_create(tree, torture, &(io.smb2)); + torture_assert_ntstatus_ok(torture, status, "smb2_create dir"); + d1 = io.smb2.out.file.handle; + + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.create_flags = 0; + io.smb2.in.desired_access = 0x0017019f; + io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.smb2.in.share_access = 0; + io.smb2.in.alloc_size = 0; + io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = BASEDIR "\\file.txt"; + + status = smb2_create(tree, torture, &(io.smb2)); + torture_assert_ntstatus_ok(torture, status, "smb2_create file"); + h1 = io.smb2.out.file.handle; + + if (!server_is_osx) { + torture_comment(torture, "Renaming directory without AAPL, must fail\n"); + + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = d1; + sinfo.rename_information.in.overwrite = 0; + sinfo.rename_information.in.root_fid = 0; + sinfo.rename_information.in.new_name = renamedir; + status = smb2_setinfo_file(tree, &sinfo); + + torture_assert_ntstatus_equal(torture, status, + NT_STATUS_ACCESS_DENIED, + "smb2_setinfo_file"); + } + + status = smb2_util_close(tree, d1); + torture_assert_ntstatus_ok(torture, status, "smb2_util_close\n"); + ZERO_STRUCT(d1); + + torture_comment(torture, "Enabling AAPL\n"); + + ret = enable_aapl(torture, tree); + torture_assert(torture, ret == true, "enable_aapl failed"); + + torture_comment(torture, "Renaming directory with AAPL\n"); + + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.desired_access = 0x0017019f; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.smb2.in.share_access = 0; + io.smb2.in.alloc_size = 0; + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = BASEDIR; + + status = smb2_create(tree, torture, &(io.smb2)); + torture_assert_ntstatus_ok(torture, status, "smb2_create dir"); + d1 = io.smb2.out.file.handle; + + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = d1; + sinfo.rename_information.in.overwrite = 0; + sinfo.rename_information.in.root_fid = 0; + sinfo.rename_information.in.new_name = renamedir; + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok(torture, status, "smb2_setinfo_file"); + + ZERO_STRUCT(cl.smb2); + cl.smb2.level = RAW_CLOSE_SMB2; + cl.smb2.in.file.handle = d1; + status = smb2_close(tree, &(cl.smb2)); + torture_assert_ntstatus_ok(torture, status, "smb2_close"); + ZERO_STRUCT(d1); + + cl.smb2.in.file.handle = h1; + status = smb2_close(tree, &(cl.smb2)); + torture_assert_ntstatus_ok(torture, status, "smb2_close"); + ZERO_STRUCT(h1); + + torture_comment(torture, "Cleaning up\n"); + + if (h1.data[0] || h1.data[1]) { + ZERO_STRUCT(cl.smb2); + cl.smb2.level = RAW_CLOSE_SMB2; + cl.smb2.in.file.handle = h1; + status = smb2_close(tree, &(cl.smb2)); + } + + smb2_util_unlink(tree, BASEDIR "\\file.txt"); + smb2_util_unlink(tree, BASEDIR "-new\\file.txt"); + smb2_deltree(tree, renamedir); + smb2_deltree(tree, BASEDIR); + return ret; +} + +static bool test_afpinfo_enoent(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME; + + torture_comment(tctx, "Opening file without AFP_AfpInfo\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + torture_comment(tctx, "Opening not existing AFP_AfpInfo\n"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */ + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpInfo stream"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_create_delete_on_close(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME; + const char *type_creator = "SMB,OLE!"; + AfpInfo *info = NULL; + const char *streams_basic[] = { + "::$DATA" + }; + const char *streams_afpinfo[] = { + "::$DATA", + AFPINFO_STREAM + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Checking whether create with delete-on-close work with AFP_AfpInfo\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + torture_comment(tctx, "Opening not existing AFP_AfpInfo\n"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */ + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpInfo stream"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpInfo stream"); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + torture_comment(tctx, "Deleting AFP_AfpInfo via create with delete-on-close\n"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(tctx, ret == true, ret, done, "Bad type/creator in AFP_AfpInfo"); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + smb2_util_close(tree, h1); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpInfo stream"); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_setinfo_delete_on_close(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + union smb_setfileinfo sfinfo; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME; + const char *type_creator = "SMB,OLE!"; + AfpInfo *info = NULL; + const char *streams[] = { + AFPINFO_STREAM, + "::$DATA" + }; + const char *streams_basic[] = { + "::$DATA" + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Deleting AFP_AfpInfo via setinfo with delete-on-close\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + /* Delete stream via setinfo delete-on-close */ + ZERO_STRUCT(sfinfo); + sfinfo.disposition_info.in.delete_on_close = 1; + sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION; + sfinfo.generic.in.file.handle = h1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set delete-on-close failed"); + + ret = check_stream_list(tree, tctx, fname, 2, streams, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_DELETE_PENDING, + ret, done, "Got unexpected AFP_AfpInfo stream"); + + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpInfo stream"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_setinfo_eof(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + union smb_setfileinfo sfinfo; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPINFO_STREAM_NAME; + const char *type_creator = "SMB,OLE!"; + AfpInfo *info = NULL; + const char *streams_afpinfo[] = { + "::$DATA", + AFPINFO_STREAM + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Set AFP_AfpInfo EOF to 61, 1 and 0\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + torture_comment(tctx, "Set AFP_AfpInfo EOF to 61\n"); + + /* Test setinfo end-of-file info */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 61; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_ALLOTTED_SPACE_EXCEEDED, + ret, done, "set eof 61 failed"); + + torture_comment(tctx, "Set AFP_AfpInfo EOF to 1\n"); + + /* Truncation returns success, but has no effect */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, + ret, done, "set eof 1 failed"); + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(tctx, ret == true, ret, done, "FinderInfo changed"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + /* + * Delete stream via setinfo end-of-file info to 0, should + * return success but stream MUST NOT deleted + */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set eof 0 failed"); + + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(tctx, ret == true, ret, done, "FinderInfo changed"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_afpinfo_all0(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h1 = {{0}}; + struct smb2_handle baseh = {{0}}; + union smb_setfileinfo setfinfo; + union smb_fileinfo getfinfo; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPINFO_STREAM; + const char *type_creator = "SMB,OLE!"; + AfpInfo *info = NULL; + char *infobuf = NULL; + const char *streams_basic[] = { + "::$DATA" + }; + const char *streams_afpinfo[] = { + "::$DATA", + AFPINFO_STREAM + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Write all 0 to AFP_AfpInfo and see what happens\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + /* Write all 0 to AFP_AfpInfo */ + memset(info->afpi_FinderInfo, 0, AFP_FinderSize); + infobuf = torture_afpinfo_pack(mem_ctx, info); + torture_assert_not_null_goto(tctx, infobuf, ret, done, + "torture_afpinfo_pack failed\n"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.fname = fname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + baseh = create.out.file.handle; + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + h1 = create.out.file.handle; + + status = smb2_util_write(tree, h1, infobuf, 0, AFP_INFO_SIZE); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + /* + * Get stream information on open handle, must return only default + * stream, the AFP_AfpInfo stream must not be returned. + */ + + ZERO_STRUCT(getfinfo); + getfinfo.generic.level = RAW_FILEINFO_STREAM_INFORMATION; + getfinfo.generic.in.file.handle = baseh; + + status = smb2_getinfo_file(tree, tctx, &getfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "get stream info\n"); + + torture_assert_int_equal_goto(tctx, getfinfo.stream_info.out.num_streams, + 1, ret, done, "stream count"); + + smb2_util_close(tree, baseh); + ZERO_STRUCT(baseh); + + /* + * Try to set some file-basic-info (time) on the stream. This catches + * naive implementation mistakes that simply deleted the backing store + * from the filesystem in the zero-out step. + */ + + ZERO_STRUCT(setfinfo); + unix_to_nt_time(&setfinfo.basic_info.in.write_time, time(NULL)); + setfinfo.basic_info.in.attrib = 0x20; + setfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; + setfinfo.generic.in.file.handle = h1; + + status = smb2_setinfo_file(tree, &setfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list"); + + smb2_util_close(tree, h1); + ZERO_STRUCT(h1); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + +done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree, h1); + } + if (!smb2_util_handle_empty(baseh)) { + smb2_util_close(tree, baseh); + } + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_create_delete_on_close_resource(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME; + const char *streams_basic[] = { + "::$DATA" + }; + const char *streams_afpresource[] = { + "::$DATA", + AFPRESOURCE_STREAM + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Checking whether create with delete-on-close is ignored for AFP_AfpResource\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok(tctx, status, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + torture_comment(tctx, "Opening not existing AFP_AfpResource\n"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; /* stat open */ + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpResource stream"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Got unexpected AFP_AfpResource stream"); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + torture_comment(tctx, "Trying to delete AFP_AfpResource via create with delete-on-close\n"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 10, "1234567890"); + torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM_NAME, + 0, 10, 0, 10, "1234567890"); + torture_assert_goto(tctx, ret == true, ret, done, "Bad content from AFP_AfpResource"); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM_NAME, + 0, 10, 0, 10, "1234567890"); + torture_assert_goto(tctx, ret == true, ret, done, "Bad content from AFP_AfpResource"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_setinfo_delete_on_close_resource(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + union smb_setfileinfo sfinfo; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME; + const char *streams_afpresource[] = { + "::$DATA", + AFPRESOURCE_STREAM + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + torture_comment(tctx, "Trying to delete AFP_AfpResource via setinfo with delete-on-close\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 10, 10, "1234567890"); + torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE | SEC_STD_SYNCHRONIZE | SEC_STD_DELETE; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + /* Try to delete stream via setinfo delete-on-close */ + ZERO_STRUCT(sfinfo); + sfinfo.disposition_info.in.delete_on_close = 1; + sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION; + sfinfo.generic.in.file.handle = h1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set delete-on-close failed"); + + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 2, streams_afpresource, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Got unexpected AFP_AfpResource stream"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +static bool test_setinfo_eof_resource(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + union smb_setfileinfo sfinfo; + union smb_fileinfo finfo; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file" AFPRESOURCE_STREAM_NAME; + const char *streams_basic[] = { + "::$DATA" + }; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new"); + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + torture_comment(tctx, "Set AFP_AfpResource EOF to 1 and 0\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir"); + smb2_util_close(tree, h1); + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 10, 10, "1234567890"); + torture_assert_goto(tctx, ret == true, ret, done, "Writing to AFP_AfpResource failed"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + torture_comment(tctx, "Set AFP_AfpResource EOF to 1\n"); + + /* Test setinfo end-of-file info */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, + ret, done, "set eof 1 failed"); + + smb2_util_close(tree, h1); + + /* Check size == 1 */ + ZERO_STRUCT(create); + create.in.fname = sname; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION; + finfo.generic.in.file.handle = h1; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed"); + + smb2_util_close(tree, h1); + + torture_assert_goto(tctx, finfo.all_info.out.size == 1, ret, done, "size != 1"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + /* + * Delete stream via setinfo end-of-file info to 0, this + * should delete the stream. + */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "set eof 0 failed"); + + smb2_util_close(tree, h1); + + ret = check_stream_list(tree, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ZERO_STRUCT(create); + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.desired_access = SEC_FILE_ALL; + create.in.fname = sname; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION; + + status = smb2_create(tree, mem_ctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "smb2_create failed"); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +/* + * This tests that right after creating the AFP_AfpInfo stream, + * reading from the stream returns an empty, default metadata blob of + * 60 bytes. + * + * NOTE: against OS X SMB server this only works if the read request + * is compounded with the create that created the stream, is fails + * otherwise. We don't care... + */ +static bool test_null_afpinfo(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = "test_null_afpinfo"; + const char *sname = "test_null_afpinfo" AFPINFO_STREAM_NAME; + NTSTATUS status; + bool ret = true; + struct smb2_request *req[3]; + struct smb2_handle handle; + struct smb2_create create; + struct smb2_read read; + AfpInfo *afpinfo = NULL; + char *afpinfo_buf = NULL; + const char *type_creator = "SMB,OLE!"; + struct smb2_handle handle2; + struct smb2_read r; + + torture_comment(tctx, "Checking create of AfpInfo stream\n"); + + smb2_util_unlink(tree, fname); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA; + create.in.share_access = FILE_SHARE_READ | FILE_SHARE_DELETE; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; + create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + create.in.fname = sname; + + smb2_transport_compound_start(tree->session->transport, 2); + + req[0] = smb2_create_send(tree, &create); + + handle.data[0] = UINT64_MAX; + handle.data[1] = UINT64_MAX; + + smb2_transport_compound_set_related(tree->session->transport, true); + + ZERO_STRUCT(read); + read.in.file.handle = handle; + read.in.length = AFP_INFO_SIZE; + req[1] = smb2_read_send(tree, &read); + + status = smb2_create_recv(req[0], tree, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_recv failed"); + + handle = create.out.file.handle; + + status = smb2_read_recv(req[1], tree, &read); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_read_recv failed"); + + status = torture_smb2_testfile_access(tree, sname, &handle2, + SEC_FILE_READ_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + r = (struct smb2_read) { + .in.file.handle = handle2, + .in.length = AFP_INFO_SIZE, + }; + + status = smb2_read(tree, tree, &r); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + smb2_util_close(tree, handle2); + + afpinfo = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, afpinfo != NULL, ret, done, "torture_afpinfo_new failed"); + + memcpy(afpinfo->afpi_FinderInfo, type_creator, 8); + + afpinfo_buf = torture_afpinfo_pack(tctx, afpinfo); + torture_assert_goto(tctx, afpinfo_buf != NULL, ret, done, "torture_afpinfo_new failed"); + + status = smb2_util_write(tree, handle, afpinfo_buf, 0, AFP_INFO_SIZE); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write failed"); + + smb2_util_close(tree, handle); + + ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + +done: + smb2_util_unlink(tree, fname); + talloc_free(mem_ctx); + return ret; +} + +static bool test_delete_file_with_rfork(struct torture_context *tctx, + struct smb2_tree *tree) +{ + const char *fname = "torture_write_rfork_io"; + const char *rfork_content = "1234567890"; + NTSTATUS status; + bool ret = true; + + smb2_util_unlink(tree, fname); + + torture_comment(tctx, "Test deleting file with resource fork\n"); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed\n"); + + ret = write_stream(tree, __location__, tctx, tctx, + fname, AFPRESOURCE_STREAM_NAME, + 10, 10, rfork_content); + torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed\n"); + + ret = check_stream(tree, __location__, tctx, tctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 20, 10, 10, rfork_content); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed\n"); + + status = smb2_util_unlink(tree, fname); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "check_stream failed\n"); + +done: + return ret; +} + +static bool test_rename_and_read_rsrc(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create, create2; + struct smb2_handle h1, h2; + const char *fname = "test_rename_openfile"; + const char *sname = "test_rename_openfile" AFPRESOURCE_STREAM_NAME; + const char *fname_renamed = "test_rename_openfile_renamed"; + const char *data = "1234567890"; + union smb_setfileinfo sinfo; + bool server_is_macos = torture_setting_bool(tctx, "osx", false); + NTSTATUS expected_status; + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + torture_comment(tctx, "Create file with resource fork\n"); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + ret = write_stream(tree, __location__, tctx, tctx, + fname, AFPRESOURCE_STREAM_NAME, 0, 10, data); + torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed"); + + torture_comment(tctx, "Open resource fork\n"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_ALL; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; + create.in.fname = sname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h1 = create.out.file.handle; + + torture_comment(tctx, "Rename base file\n"); + + ZERO_STRUCT(create2); + create2.in.desired_access = SEC_FILE_ALL; + create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create2.in.create_disposition = NTCREATEX_DISP_OPEN; + create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; + create2.in.fname = fname; + + status = smb2_create(tree, tctx, &create2); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + h2 = create2.out.file.handle; + + ZERO_STRUCT(sinfo); + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION; + sinfo.rename_information.in.file.handle = h2; + sinfo.rename_information.in.overwrite = 0; + sinfo.rename_information.in.root_fid = 0; + sinfo.rename_information.in.new_name = fname_renamed; + + if (server_is_macos) { + expected_status = NT_STATUS_SHARING_VIOLATION; + } else { + expected_status = NT_STATUS_ACCESS_DENIED; + } + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_equal_goto( + tctx, status, expected_status, ret, done, + "smb2_setinfo_file failed"); + + smb2_util_close(tree, h2); + + status = smb2_util_write(tree, h1, "foo", 0, 3); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "write failed\n"); + + smb2_util_close(tree, h1); + +done: + smb2_util_unlink(tree, fname); + smb2_util_unlink(tree, fname_renamed); + + return ret; +} + +static bool test_readdir_attr_illegal_ntfs(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *name = "test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */ + const char *fname = BASEDIR "\\test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */ + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + struct smb2_create io; + AfpInfo *info; + const char *type_creator = "SMB,OLE!"; + struct smb2_find f; + unsigned int count; + union smb_search_data *d; + uint64_t rfork_len; + unsigned int i; + + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed"); + smb2_util_close(tree, testdirh); + + torture_comment(tctx, "Enabling AAPL\n"); + + ret = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + /* + * Now that Requested AAPL extensions are enabled, setup some + * Mac files with metadata and resource fork + */ + + torture_comment(tctx, "Preparing file\n"); + + ret = torture_setup_file(mem_ctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed"); + + info = torture_afpinfo_new(mem_ctx); + torture_assert_not_null_goto(tctx, info, ret, done, "torture_afpinfo_new failed"); + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ret = write_stream(tree, __location__, tctx, mem_ctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 3, "foo"); + torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed"); + + /* + * Ok, file is prepared, now call smb2/find + */ + + torture_comment(tctx, "Issue find\n"); + + ZERO_STRUCT(io); + io.in.desired_access = SEC_RIGHTS_DIR_READ; + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE | + NTCREATEX_SHARE_ACCESS_DELETE); + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.fname = BASEDIR; + status = smb2_create(tree, tctx, &io); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed"); + + ZERO_STRUCT(f); + f.in.file.handle = io.out.file.handle; + f.in.pattern = "*"; + f.in.max_response_size = 0x1000; + f.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_level failed"); + + status = smb2_util_close(tree, io.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed"); + + torture_comment(tctx, "Checking find response with enriched macOS metadata\n"); + + for (i = 0; i < count; i++) { + const char *found = d[i].id_both_directory_info.name.s; + + if (!strcmp(found, ".") || !strcmp(found, "..")) + continue; + if (strncmp(found, "._", 2) == 0) { + continue; + } + break; + } + + torture_assert_str_equal_goto(tctx, + d[i].id_both_directory_info.name.s, name, + ret, done, "bad name"); + + rfork_len = BVAL(d[i].id_both_directory_info.short_name_buf, 0); + torture_assert_int_equal_goto(tctx, rfork_len, 3, ret, done, "bad resource fork length"); + + torture_assert_mem_equal_goto(tctx, type_creator, + d[i].id_both_directory_info.short_name_buf + 8, + 8, ret, done, "Bad FinderInfo"); +done: + smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_invalid_afpinfo(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + const char *fname = "filtest_invalid_afpinfo"; + const char *sname = "filtest_invalid_afpinfo" AFPINFO_STREAM_NAME; + struct smb2_create create; + const char *streams_basic[] = { + "::$DATA" + }; + const char *streams_afpinfo[] = { + "::$DATA", + AFPINFO_STREAM + }; + NTSTATUS status; + bool ret = true; + + if (tree2 == NULL) { + torture_skip_goto(tctx, done, "need second share without fruit\n"); + } + + torture_comment(tctx, "Testing invalid AFP_AfpInfo stream\n"); + + ret = torture_setup_file(tctx, tree2, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + ret = write_stream(tree2, __location__, tctx, tctx, + fname, AFPINFO_STREAM_NAME, + 0, 3, "foo"); + torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed"); + + ret = check_stream_list(tree2, tctx, fname, 2, streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + torture_comment(tctx, "Listing streams, bad AFPINFO stream must not be present\n"); + + ret = check_stream_list(tree1, tctx, fname, 1, streams_basic, false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + torture_comment(tctx, "Try to open AFPINFO stream, must fail\n"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_ALL; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION; + create.in.fname = sname; + + status = smb2_create(tree1, tctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Stream still around?"); + +done: + smb2_util_unlink(tree1, fname); + return ret; +} + +static bool test_writing_afpinfo(struct torture_context *tctx, + struct smb2_tree *tree) +{ + const char *fname = "filtest_invalid_afpinfo"; + const char *sname = "filtest_invalid_afpinfo" AFPINFO_STREAM; + const char *streams_afpinfo[] = { + "::$DATA", + AFPINFO_STREAM + }; + bool ret = true; + static AfpInfo *afpi = NULL; + char *buf = NULL; + char *afpi_buf = NULL; + char *zero_buf = NULL; + bool broken_osx = torture_setting_bool(tctx, "broken_osx_45759458", false); + off_t min_offset_for_2streams = 16; + int i; + NTSTATUS status; + struct test_sizes { + off_t offset; + size_t size; + bool expected_result; + } test_sizes[] = { + { 0, 1, false}, + { 0, 2, false}, + { 0, 3, true}, + { 0, 4, true}, + { 0, 14, true}, + { 0, 15, true}, + { 0, 16, true}, + { 0, 24, true}, + { 0, 34, true}, + { 0, 44, true}, + { 0, 54, true}, + { 0, 55, true}, + { 0, 56, true}, + { 0, 57, true}, + { 0, 58, true}, + { 0, 59, true}, + { 0, 60, true}, + { 0, 61, true}, + { 0, 64, true}, + { 0, 1024, true}, + { 0, 10064, true}, + + { 1, 1, false}, + { 1, 2, false}, + { 1, 3, false}, + { 1, 4, false}, + { 1, 14, false}, + { 1, 15, false}, + { 1, 16, false}, + { 1, 24, false}, + { 1, 34, false}, + { 1, 44, false}, + { 1, 54, false}, + { 1, 55, false}, + { 1, 56, false}, + { 1, 57, false}, + { 1, 58, false}, + { 1, 59, false}, + { 1, 60, true}, + { 1, 61, true}, + { 1, 1024, true}, + { 1, 10064, true}, + + { 30, 1, false}, + { 30, 2, false}, + { 30, 3, false}, + { 30, 4, false}, + { 30, 14, false}, + { 30, 15, false}, + { 30, 16, false}, + { 30, 24, false}, + { 30, 34, false}, + { 30, 44, false}, + { 30, 54, false}, + { 30, 55, false}, + { 30, 56, false}, + { 30, 57, false}, + { 30, 58, false}, + { 30, 59, false}, + { 30, 60, true}, + { 30, 61, true}, + { 30, 1024, true}, + { 30, 10064, true}, + + { 58, 1, false}, + { 58, 2, false}, + { 58, 3, false}, + { 58, 4, false}, + { 58, 14, false}, + { 58, 15, false}, + { 58, 16, false}, + { 58, 24, false}, + { 58, 34, false}, + { 58, 44, false}, + { 58, 54, false}, + { 58, 55, false}, + { 58, 56, false}, + { 58, 57, false}, + { 58, 58, false}, + { 58, 59, false}, + { 58, 60, true}, + { 58, 61, true}, + { 58, 1024, true}, + { 58, 10064, true}, + + { 59, 1, false}, + { 59, 2, false}, + { 59, 3, false}, + { 59, 4, false}, + { 59, 14, false}, + { 59, 15, false}, + { 59, 16, false}, + { 59, 24, false}, + { 59, 34, false}, + { 59, 44, false}, + { 59, 54, false}, + { 59, 55, false}, + { 59, 56, false}, + { 59, 57, false}, + { 59, 58, false}, + { 59, 59, false}, + { 59, 60, true}, + { 59, 61, true}, + { 59, 1024, true}, + { 59, 10064, true}, + + { 60, 1, false}, + { 60, 2, false}, + { 60, 3, false}, + { 60, 4, false}, + { 60, 14, false}, + { 60, 15, false}, + { 60, 16, false}, + { 60, 24, false}, + { 60, 34, false}, + { 60, 44, false}, + { 60, 54, false}, + { 60, 55, false}, + { 60, 56, false}, + { 60, 57, false}, + { 60, 58, false}, + { 60, 59, false}, + { 60, 60, true}, + { 60, 61, true}, + { 60, 1024, true}, + { 60, 10064, true}, + + { 61, 1, false}, + { 61, 2, false}, + { 61, 3, false}, + { 61, 4, false}, + { 61, 14, false}, + { 61, 15, false}, + { 61, 16, false}, + { 61, 24, false}, + { 61, 34, false}, + { 61, 44, false}, + { 61, 54, false}, + { 61, 55, false}, + { 61, 56, false}, + { 61, 57, false}, + { 61, 58, false}, + { 61, 59, false}, + { 61, 60, true}, + { 61, 61, true}, + { 61, 1024, true}, + { 61, 10064, true}, + + { 10000, 1, false}, + { 10000, 2, false}, + { 10000, 3, false}, + { 10000, 4, false}, + { 10000, 14, false}, + { 10000, 15, false}, + { 10000, 16, false}, + { 10000, 24, false}, + { 10000, 34, false}, + { 10000, 44, false}, + { 10000, 54, false}, + { 10000, 55, false}, + { 10000, 56, false}, + { 10000, 57, false}, + { 10000, 58, false}, + { 10000, 59, false}, + { 10000, 60, true}, + { 10000, 61, true}, + { 10000, 1024, true}, + { 10000, 10064, true}, + + { -1, 0, false}, + }; + + afpi = torture_afpinfo_new(tctx); + torture_assert_not_null_goto(tctx, afpi, ret, done, + "torture_afpinfo_new failed\n"); + + memcpy(afpi->afpi_FinderInfo, "FOO BAR ", 8); + + buf = torture_afpinfo_pack(afpi, afpi); + torture_assert_not_null_goto(tctx, buf, ret, done, + "torture_afpinfo_pack failed\n"); + + afpi_buf = talloc_zero_array(tctx, char, 10064); + torture_assert_not_null_goto(tctx, afpi_buf, ret, done, + "talloc_zero_array failed\n"); + memcpy(afpi_buf, buf, 60); + + zero_buf = talloc_zero_array(tctx, char, 10064); + torture_assert_not_null_goto(tctx, zero_buf, ret, done, + "talloc_zero_array failed\n"); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file\n"); + + for (i = 0; test_sizes[i].offset != -1; i++) { + struct smb2_handle h; + struct smb2_create c; + int expected_num_streams; + size_t fi_check_size; + + torture_comment(tctx, + "Test %d: offset=%jd size=%zu result=%s\n", + i, + (intmax_t)test_sizes[i].offset, + test_sizes[i].size, + test_sizes[i].expected_result ? "true":"false"); + + + c = (struct smb2_create) { + .in.desired_access = SEC_FILE_WRITE_DATA, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN_IF, + .in.fname = sname, + }; + + status = smb2_create(tree, tree, &c); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create\n"); + h = c.out.file.handle; + + status = smb2_util_write(tree, + h, + zero_buf, + test_sizes[i].offset, + test_sizes[i].size); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_INVALID_PARAMETER, + ret, done, "smb2_util_write\n"); + + status = smb2_util_write(tree, + h, + afpi_buf, + test_sizes[i].offset, + test_sizes[i].size); + smb2_util_close(tree, h); + if (test_sizes[i].expected_result == true) { + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write\n"); + } else { + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_INVALID_PARAMETER, + ret, done, "smb2_util_write\n"); + } + + if (broken_osx) { + /* + * Currently macOS has a bug (Radar #45759458) where it + * writes more bytes then requested from uninitialized + * memory to the filesystem. That means it will likely + * write data to FinderInfo so the stream is not empty + * and thus listed when the number of streams is + * queried. + */ + min_offset_for_2streams = 2; + } + + if ((test_sizes[i].expected_result == true) && + (test_sizes[i].size > min_offset_for_2streams)) + { + expected_num_streams = 2; + } else { + expected_num_streams = 1; + } + + ret = check_stream_list(tree, tctx, fname, + expected_num_streams, + streams_afpinfo, false); + torture_assert_goto(tctx, ret == true, ret, done, + "Bad streams\n"); + + if (test_sizes[i].expected_result == false) { + continue; + } + + if (test_sizes[i].size <= 16) { + /* + * FinderInfo with the "FOO BAR " string we wrote above + * would start at offset 16. Check whether this test + * wrote 1 byte or more. + */ + goto next; + } + + fi_check_size = test_sizes[i].size - 16; + fi_check_size = MIN(fi_check_size, 8); + + ret = check_stream(tree, __location__, + tctx, tctx, + fname, AFPINFO_STREAM, + 0, 60, 16, fi_check_size, "FOO BAR "); + torture_assert_goto(tctx, ret == true, ret, done, + "Bad streams\n"); + +next: + status = smb2_util_unlink(tree, sname); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + bool missing_ok; + + missing_ok = test_sizes[i].expected_result == false; + missing_ok |= test_sizes[i].size <= 16; + + torture_assert_goto(tctx, missing_ok, + ret, done, "smb2_util_unlink\n"); + } + } + +done: + smb2_util_unlink(tree, fname); + return ret; +} + +static bool test_zero_file_id(struct torture_context *tctx, + struct smb2_tree *tree) +{ + const char *fname = "filtest_file_id"; + struct smb2_create create = {0}; + NTSTATUS status; + bool ret = true; + uint8_t zero_file_id[8] = {0}; + + torture_comment(tctx, "Testing zero file id\n"); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = fname; + create.in.query_on_disk_id = true; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OK, ret, + done, + "test file could not be opened"); + torture_assert_mem_not_equal_goto(tctx, create.out.on_disk_id, + zero_file_id, 8, ret, done, + "unexpected zero file id"); + + smb2_util_close(tree, create.out.file.handle); + + ret = enable_aapl(tctx, tree); + torture_assert(tctx, ret == true, "enable_aapl failed"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = fname; + create.in.query_on_disk_id = true; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OK, ret, done, + "test file could not be opened with AAPL"); + torture_assert_mem_equal_goto(tctx, create.out.on_disk_id, zero_file_id, + 8, ret, done, "non-zero file id"); + + smb2_util_close(tree, create.out.file.handle); + +done: + smb2_util_unlink(tree, fname); + return ret; +} + +static bool copy_one_stream(struct torture_context *torture, + struct smb2_tree *tree, + TALLOC_CTX *tmp_ctx, + const char *src_sname, + const char *dst_sname) +{ + struct smb2_handle src_h = {{0}}; + struct smb2_handle dest_h = {{0}}; + NTSTATUS status; + union smb_ioctl io; + struct srv_copychunk_copy cc_copy; + struct srv_copychunk_rsp cc_rsp; + enum ndr_err_code ndr_ret; + bool ok = false; + + ok = test_setup_copy_chunk(torture, tree, tmp_ctx, + 1, /* 1 chunk */ + src_sname, + &src_h, 256, /* fill 256 byte src file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + dst_sname, + &dest_h, 0, /* 0 byte dest file */ + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + &cc_copy, + &io); + torture_assert_goto(torture, ok == true, ok, done, + "setup copy chunk error\n"); + + /* copy all src file data (via a single chunk desc) */ + cc_copy.chunks[0].source_off = 0; + cc_copy.chunks[0].target_off = 0; + cc_copy.chunks[0].length = 256; + + ndr_ret = ndr_push_struct_blob( + &io.smb2.in.out, tmp_ctx, &cc_copy, + (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy); + + torture_assert_ndr_success_goto(torture, ndr_ret, ok, done, + "ndr_push_srv_copychunk_copy\n"); + + status = smb2_ioctl(tree, tmp_ctx, &io.smb2); + torture_assert_ntstatus_ok_goto(torture, status, ok, done, + "FSCTL_SRV_COPYCHUNK\n"); + + ndr_ret = ndr_pull_struct_blob( + &io.smb2.out.out, tmp_ctx, &cc_rsp, + (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp); + + torture_assert_ndr_success_goto(torture, ndr_ret, ok, done, + "ndr_pull_srv_copychunk_rsp\n"); + + ok = check_copy_chunk_rsp(torture, &cc_rsp, + 1, /* chunks written */ + 0, /* chunk bytes unsuccessfully written */ + 256); /* total bytes written */ + torture_assert_goto(torture, ok == true, ok, done, + "bad copy chunk response data\n"); + + ok = check_pattern(torture, tree, tmp_ctx, dest_h, 0, 256, 0); + if (!ok) { + torture_fail(torture, "inconsistent file data\n"); + } + +done: + if (!smb2_util_handle_empty(src_h)) { + smb2_util_close(tree, src_h); + } + if (!smb2_util_handle_empty(dest_h)) { + smb2_util_close(tree, dest_h); + } + + return ok; +} + +static bool copy_finderinfo_stream(struct torture_context *torture, + struct smb2_tree *tree, + TALLOC_CTX *tmp_ctx, + const char *src_name, + const char *dst_name) +{ + struct smb2_handle src_h = {{0}}; + struct smb2_handle dest_h = {{0}}; + NTSTATUS status; + union smb_ioctl io; + struct srv_copychunk_copy cc_copy; + struct srv_copychunk_rsp cc_rsp; + enum ndr_err_code ndr_ret; + const char *type_creator = "SMB,OLE!"; + AfpInfo *info = NULL; + const char *src_name_afpinfo = NULL; + const char *dst_name_afpinfo = NULL; + bool ok = false; + + src_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", src_name, + AFPINFO_STREAM); + torture_assert_not_null_goto(torture, src_name_afpinfo, ok, done, + "talloc_asprintf failed\n"); + + dst_name_afpinfo = talloc_asprintf(tmp_ctx, "%s%s", dst_name, + AFPINFO_STREAM); + torture_assert_not_null_goto(torture, dst_name_afpinfo, ok, done, + "talloc_asprintf failed\n"); + + info = torture_afpinfo_new(tmp_ctx); + torture_assert_not_null_goto(torture, info, ok, done, + "torture_afpinfo_new failed\n"); + + memcpy(info->afpi_FinderInfo, type_creator, 8); + ok = torture_write_afpinfo(tree, torture, tmp_ctx, src_name, info); + torture_assert_goto(torture, ok == true, ok, done, + "torture_write_afpinfo failed\n"); + + ok = test_setup_copy_chunk(torture, tree, tmp_ctx, + 1, /* 1 chunk */ + src_name_afpinfo, + &src_h, 0, + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + dst_name_afpinfo, + &dest_h, 0, + SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA, + &cc_copy, + &io); + torture_assert_goto(torture, ok == true, ok, done, + "setup copy chunk error\n"); + + /* copy all src file data (via a single chunk desc) */ + cc_copy.chunks[0].source_off = 0; + cc_copy.chunks[0].target_off = 0; + cc_copy.chunks[0].length = 60; + + ndr_ret = ndr_push_struct_blob( + &io.smb2.in.out, tmp_ctx, &cc_copy, + (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy); + + torture_assert_ndr_success_goto(torture, ndr_ret, ok, done, + "ndr_push_srv_copychunk_copy\n"); + + status = smb2_ioctl(tree, tmp_ctx, &io.smb2); + torture_assert_ntstatus_ok_goto(torture, status, ok, done, + "FSCTL_SRV_COPYCHUNK\n"); + + ndr_ret = ndr_pull_struct_blob( + &io.smb2.out.out, tmp_ctx, &cc_rsp, + (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp); + + torture_assert_ndr_success_goto(torture, ndr_ret, ok, done, + "ndr_pull_srv_copychunk_rsp\n"); + + smb2_util_close(tree, src_h); + ZERO_STRUCT(src_h); + smb2_util_close(tree, dest_h); + ZERO_STRUCT(dest_h); + + ok = check_copy_chunk_rsp(torture, &cc_rsp, + 1, /* chunks written */ + 0, /* chunk bytes unsuccessfully written */ + 60); /* total bytes written */ + torture_assert_goto(torture, ok == true, ok, done, + "bad copy chunk response data\n"); + + ok = check_stream(tree, __location__, torture, tmp_ctx, + dst_name, AFPINFO_STREAM, + 0, 60, 16, 8, type_creator); + torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n"); + +done: + if (!smb2_util_handle_empty(src_h)) { + smb2_util_close(tree, src_h); + } + if (!smb2_util_handle_empty(dest_h)) { + smb2_util_close(tree, dest_h); + } + + return ok; +} + +static bool test_copy_chunk_streams(struct torture_context *torture, + struct smb2_tree *tree) +{ + const char *src_name = "src"; + const char *dst_name = "dst"; + struct names { + const char *src_sname; + const char *dst_sname; + } names[] = { + { "src:foo", "dst:foo" }, + { "src" AFPRESOURCE_STREAM, "dst" AFPRESOURCE_STREAM } + }; + size_t i; + TALLOC_CTX *tmp_ctx = NULL; + bool ok = false; + + tmp_ctx = talloc_new(tree); + torture_assert_not_null_goto(torture, tmp_ctx, ok, done, + "torture_setup_file\n"); + + smb2_util_unlink(tree, src_name); + smb2_util_unlink(tree, dst_name); + + ok = torture_setup_file(torture, tree, src_name, false); + torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n"); + ok = torture_setup_file(torture, tree, dst_name, false); + torture_assert_goto(torture, ok == true, ok, done, "torture_setup_file\n"); + + for (i = 0; i < ARRAY_SIZE(names); i++) { + ok = copy_one_stream(torture, tree, tmp_ctx, + names[i].src_sname, + names[i].dst_sname); + torture_assert_goto(torture, ok == true, ok, done, + "copy_one_stream failed\n"); + } + + ok = copy_finderinfo_stream(torture, tree, tmp_ctx, + src_name, dst_name); + torture_assert_goto(torture, ok == true, ok, done, + "copy_finderinfo_stream failed\n"); + +done: + smb2_util_unlink(tree, src_name); + smb2_util_unlink(tree, dst_name); + talloc_free(tmp_ctx); + return ok; +} + +/* + * Ensure this security descriptor has exactly one mode, uid + * and gid. + */ + +static NTSTATUS check_nfs_sd(const struct security_descriptor *psd) +{ + uint32_t i; + bool got_one_mode = false; + bool got_one_uid = false; + bool got_one_gid = false; + + if (psd->dacl == NULL) { + return NT_STATUS_INVALID_SECURITY_DESCR; + } + + for (i = 0; i < psd->dacl->num_aces; i++) { + if (dom_sid_compare_domain(&global_sid_Unix_NFS_Mode, + &psd->dacl->aces[i].trustee) == 0) { + if (got_one_mode == true) { + /* Can't have more than one. */ + return NT_STATUS_INVALID_SECURITY_DESCR; + } + got_one_mode = true; + } + } + for (i = 0; i < psd->dacl->num_aces; i++) { + if (dom_sid_compare_domain(&global_sid_Unix_NFS_Users, + &psd->dacl->aces[i].trustee) == 0) { + if (got_one_uid == true) { + /* Can't have more than one. */ + return NT_STATUS_INVALID_SECURITY_DESCR; + } + got_one_uid = true; + } + } + for (i = 0; i < psd->dacl->num_aces; i++) { + if (dom_sid_compare_domain(&global_sid_Unix_NFS_Groups, + &psd->dacl->aces[i].trustee) == 0) { + if (got_one_gid == true) { + /* Can't have more than one. */ + return NT_STATUS_INVALID_SECURITY_DESCR; + } + got_one_gid = true; + } + } + /* Must have at least one of each. */ + if (got_one_mode == false || + got_one_uid == false || + got_one_gid == false) { + return NT_STATUS_INVALID_SECURITY_DESCR; + } + return NT_STATUS_OK; +} + +static bool test_nfs_aces(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct security_ace ace; + struct dom_sid sid; + const char *fname = BASEDIR "\\nfs_aces.txt"; + struct smb2_handle h = {{0}}; + union smb_fileinfo finfo2; + union smb_setfileinfo set; + struct security_descriptor *psd = NULL; + NTSTATUS status; + bool ret = true; + bool is_osx = torture_setting_bool(tctx, "osx", false); + + if (is_osx) { + torture_skip(tctx, "Test only works with Samba\n"); + } + + ret = enable_aapl(tctx, tree); + torture_assert(tctx, ret == true, "enable_aapl failed"); + + /* clean slate ...*/ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + /* Create a test file. */ + status = torture_smb2_testfile_access(tree, + fname, + &h, + SEC_STD_READ_CONTROL | + SEC_STD_WRITE_DAC | + SEC_RIGHTS_FILE_ALL); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Get the ACL. */ + finfo2.query_secdesc.in.secinfo_flags = + SECINFO_OWNER | + SECINFO_GROUP | + SECINFO_DACL; + finfo2.generic.level = RAW_FILEINFO_SEC_DESC; + finfo2.generic.in.file.handle = h; + status = smb2_getinfo_file(tree, tctx, &finfo2); + CHECK_STATUS(status, NT_STATUS_OK); + + psd = finfo2.query_secdesc.out.sd; + + /* Ensure we have only single mode/uid/gid NFS entries. */ + status = check_nfs_sd(psd); + if (!NT_STATUS_IS_OK(status)) { + NDR_PRINT_DEBUG( + security_descriptor, + discard_const_p(struct security_descriptor, psd)); + } + CHECK_STATUS(status, NT_STATUS_OK); + + /* Add a couple of extra NFS uids and gids. */ + sid_compose(&sid, &global_sid_Unix_NFS_Users, 27); + init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0); + status = security_descriptor_dacl_add(psd, &ace); + CHECK_STATUS(status, NT_STATUS_OK); + status = security_descriptor_dacl_add(psd, &ace); + CHECK_STATUS(status, NT_STATUS_OK); + + sid_compose(&sid, &global_sid_Unix_NFS_Groups, 300); + init_sec_ace(&ace, &sid, SEC_ACE_TYPE_ACCESS_DENIED, 0, 0); + status = security_descriptor_dacl_add(psd, &ace); + CHECK_STATUS(status, NT_STATUS_OK); + status = security_descriptor_dacl_add(psd, &ace); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Now set on the file handle. */ + set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + set.set_secdesc.in.file.handle = h; + set.set_secdesc.in.secinfo_flags = SECINFO_DACL; + set.set_secdesc.in.sd = psd; + status = smb2_setinfo_file(tree, &set); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Get the ACL again. */ + finfo2.query_secdesc.in.secinfo_flags = + SECINFO_OWNER | + SECINFO_GROUP | + SECINFO_DACL; + finfo2.generic.level = RAW_FILEINFO_SEC_DESC; + finfo2.generic.in.file.handle = h; + status = smb2_getinfo_file(tree, tctx, &finfo2); + CHECK_STATUS(status, NT_STATUS_OK); + + psd = finfo2.query_secdesc.out.sd; + + /* Ensure we have only single mode/uid/gid NFS entries. */ + status = check_nfs_sd(psd); + if (!NT_STATUS_IS_OK(status)) { + NDR_PRINT_DEBUG( + security_descriptor, + discard_const_p(struct security_descriptor, psd)); + } + CHECK_STATUS(status, NT_STATUS_OK); + +done: + if (!smb2_util_handle_empty(h)) { + smb2_util_close(tree, h); + } + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +static bool test_setinfo_stream_eof(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool ret = true; + NTSTATUS status; + struct smb2_create create; + union smb_setfileinfo sfinfo; + union smb_fileinfo finfo; + struct smb2_handle h1; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\file"; + const char *sname = BASEDIR "\\file:foo"; + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, + "talloc_new failed\n"); + + ret = enable_aapl(tctx, tree); + torture_assert(tctx, ret == true, "enable_aapl failed"); + + torture_comment(tctx, "Test setting EOF on a stream\n"); + + smb2_deltree(tree, BASEDIR); + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + + status = torture_smb2_testfile(tree, fname, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + smb2_util_close(tree, h1); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + status = smb2_util_write(tree, h1, "1234567890", 0, 10); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + smb2_util_close(tree, h1); + + /* + * Test setting EOF to 21 + */ + + torture_comment(tctx, "Setting stream EOF to 21\n"); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 21; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, + ret, done, "set EOF 21 failed\n"); + + smb2_util_close(tree, h1); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION; + finfo.generic.in.file.handle = h1; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed"); + + smb2_util_close(tree, h1); + + torture_assert_goto(tctx, finfo.standard_info.out.size == 21, + ret, done, "size != 21\n"); + + /* + * Test setting EOF to 0 + */ + + torture_comment(tctx, "Setting stream EOF to 0\n"); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set eof 0 failed\n"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = sname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, + "Unexpected status\n"); + + smb2_util_close(tree, h1); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = sname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, + "Unexpected status\n"); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION; + finfo.generic.in.file.handle = h1; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + smb2_util_close(tree, h1); + + torture_assert_goto(tctx, finfo.standard_info.out.size == 0, + ret, done, "size != 0\n"); + + /* + * Test setinfo end-of-file info to 1 + */ + + torture_comment(tctx, "Setting stream EOF to 1\n"); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set EOF 1 failed\n"); + + smb2_util_close(tree, h1); + + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_STANDARD_INFORMATION; + finfo.generic.in.file.handle = h1; + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + smb2_util_close(tree, h1); + + torture_assert_goto(tctx, finfo.standard_info.out.size == 1, + ret, done, "size != 1\n"); + + /* + * Test setting EOF to 0 with AAPL enabled, should delete stream + */ + + torture_comment(tctx, "Enabling AAPL extensions\n"); + + ret = enable_aapl(tctx, tree); + torture_assert(tctx, ret == true, "enable_aapl failed\n"); + + torture_comment(tctx, "Setting stream EOF to 0\n"); + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set eof 0 failed\n"); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = sname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, + "Unexpected status\n"); + + smb2_util_close(tree, h1); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = sname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, + "Unexpected status\n"); + + torture_comment( + tctx, "Setting main file EOF to 1 to force 0-truncate\n"); + + status = torture_smb2_testfile_access( + tree, + fname, + &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 1; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto( + tctx, + status, + ret, + done, + "set eof 1 failed\n"); + + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto( + tctx, + status, + ret, + done, + "set eof 0 failed\n"); + + smb2_util_close(tree, h1); + + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_ATTRIBUTE; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = fname; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + smb2_util_close(tree, h1); + + torture_comment(tctx, "Writing to stream after setting EOF to 0\n"); + status = torture_smb2_testfile_access(tree, sname, &h1, + SEC_FILE_WRITE_DATA); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + status = smb2_util_write(tree, h1, "1234567890", 0, 10); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + ZERO_STRUCT(sfinfo); + sfinfo.generic.in.file.handle = h1; + sfinfo.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION; + sfinfo.position_information.in.position = 0; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set eof 0 failed\n"); + + status = smb2_util_write(tree, h1, "1234567890", 0, 10); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + smb2_util_close(tree, h1); + +done: + smb2_util_unlink(tree, fname); + smb2_util_rmdir(tree, BASEDIR); + return ret; +} + +#define MAX_STREAMS 16 + +struct tcase { + const char *name; + uint32_t access; + const char *write_data; + size_t write_size; + struct tcase_results { + size_t size; + NTSTATUS initial_status; + NTSTATUS final_status; + int num_streams_open_handle; + const char *streams_open_handle[MAX_STREAMS]; + int num_streams_closed_handle; + const char *streams_closed_handle[MAX_STREAMS]; + } create, write, overwrite, eof, doc; +}; + +typedef enum {T_CREATE, T_WRITE, T_OVERWRITE, T_EOF, T_DOC} subtcase_t; + +static bool test_empty_stream_do_checks( + struct torture_context *tctx, + struct smb2_tree *tree, + struct smb2_tree *tree2, + struct tcase *tcase, + TALLOC_CTX *mem_ctx, + struct smb2_handle baseh, + struct smb2_handle streamh, + subtcase_t subcase) +{ + bool ret = false; + NTSTATUS status; + struct smb2_handle h1; + union smb_fileinfo finfo; + struct tcase_results *tcase_results = NULL; + + switch (subcase) { + case T_CREATE: + tcase_results = &tcase->create; + break; + case T_OVERWRITE: + tcase_results = &tcase->overwrite; + break; + case T_WRITE: + tcase_results = &tcase->write; + break; + case T_EOF: + tcase_results = &tcase->eof; + break; + case T_DOC: + tcase_results = &tcase->doc; + break; + } + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_STANDARD_INFORMATION, + .generic.in.file.handle = streamh, + }; + + /* + * Test: check size, same client + */ + + status = smb2_getinfo_file(tree, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + torture_assert_int_equal_goto(tctx, finfo.standard_info.out.size, + tcase_results->size, + ret, done, "Wrong size\n"); + + /* + * Test: open, same client + */ + + status = torture_smb2_open(tree, tcase->name, + SEC_FILE_READ_ATTRIBUTE, &h1); + torture_assert_ntstatus_equal_goto(tctx, status, + tcase_results->initial_status, + ret, done, + "smb2_create failed\n"); + if (NT_STATUS_IS_OK(status)) { + status = smb2_util_close(tree, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed\n"); + } + + /* + * Test: check streams, same client + */ + + ret = check_stream_list_handle(tree, tctx, baseh, + tcase_results->num_streams_open_handle, + tcase_results->streams_open_handle, + false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + /* + * Test: open, different client + */ + + status = torture_smb2_open(tree2, tcase->name, + SEC_FILE_READ_ATTRIBUTE, &h1); + torture_assert_ntstatus_equal_goto(tctx, status, + tcase_results->initial_status, + ret, done, + "smb2_create failed\n"); + if (NT_STATUS_IS_OK(status)) { + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_STANDARD_INFORMATION, + .generic.in.file.handle = h1, + }; + + /* + * Test: check size, different client + */ + + status = smb2_getinfo_file(tree2, mem_ctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + torture_assert_int_equal_goto(tctx, finfo.standard_info.out.size, + tcase_results->size, + ret, done, "Wrong size\n"); + + /* + * Test: check streams, different client + */ + + ret = check_stream_list(tree2, tctx, BASEDIR "\\file", + tcase_results->num_streams_open_handle, + tcase_results->streams_open_handle, + false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + status = smb2_util_close(tree2, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed\n"); + } + + status = smb2_util_close(tree, streamh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed\n"); + + /* + * Test: open after close, same client + */ + + status = torture_smb2_open(tree, tcase->name, + SEC_FILE_READ_DATA, &h1); + torture_assert_ntstatus_equal_goto(tctx, status, + tcase_results->final_status, + ret, done, + "smb2_create failed\n"); + if (NT_STATUS_IS_OK(status)) { + status = smb2_util_close(tree, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed\n"); + } + + /* + * Test: open after close, different client + */ + + status = torture_smb2_open(tree2, tcase->name, + SEC_FILE_READ_DATA, &h1); + torture_assert_ntstatus_equal_goto(tctx, status, + tcase_results->final_status, + ret, done, + "smb2_create failed\n"); + if (NT_STATUS_IS_OK(status)) { + status = smb2_util_close(tree2, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed\n"); + } + + /* + * Test: check streams after close, same client + */ + + ret = check_stream_list_handle(tree, tctx, baseh, + tcase_results->num_streams_closed_handle, + tcase_results->streams_closed_handle, + false); + torture_assert_goto(tctx, ret == true, ret, done, "Bad streams"); + + ret = true; + +done: + smb2_util_close(tree, streamh); + smb2_util_close(tree, baseh); + return ret; +} + +static bool test_empty_stream_do_one( + struct torture_context *tctx, + struct smb2_tree *tree, + struct smb2_tree *tree2, + struct tcase *tcase) +{ + bool ret = false; + NTSTATUS status; + struct smb2_handle baseh = {{0}}; + struct smb2_handle streamh; + struct smb2_create create; + union smb_setfileinfo sfinfo; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + + torture_comment(tctx, "Testing stream [%s]\n", tcase->name); + + torture_assert_goto(tctx, mem_ctx != NULL, ret, done, "talloc_new\n"); + + /* + * Subtest: create + */ + torture_comment(tctx, "Subtest: T_CREATE\n"); + + status = smb2_util_unlink(tree, BASEDIR "\\file"); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + + status = torture_smb2_testfile_access(tree, BASEDIR "\\file", + &baseh, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = torture_smb2_testfile_access(tree, tcase->name, &streamh, + tcase->access); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase, + mem_ctx, baseh, streamh, T_CREATE); + torture_assert_goto(tctx, ret, ret, done, "test failed\n"); + + if (!(tcase->access & SEC_FILE_WRITE_DATA)) { + /* + * All subsequent tests require write access + */ + ret = true; + goto done; + } + + /* + * Subtest: create and write + */ + torture_comment(tctx, "Subtest: T_WRITE\n"); + + status = smb2_util_unlink(tree, BASEDIR "\\file"); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + + status = torture_smb2_testfile_access(tree, BASEDIR "\\file", + &baseh, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = torture_smb2_testfile_access(tree, tcase->name, &streamh, + tcase->access); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = smb2_util_write(tree, streamh, tcase->write_data, 0, + tcase->write_size); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_open failed\n"); + + ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase, + mem_ctx, baseh, streamh, T_WRITE); + torture_assert_goto(tctx, ret, ret, done, "test failed\n"); + + /* + * Subtest: overwrite + */ + torture_comment(tctx, "Subtest: T_OVERWRITE\n"); + + status = smb2_util_unlink(tree, BASEDIR "\\file"); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + + status = torture_smb2_testfile_access(tree, BASEDIR "\\file", + &baseh, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .in.fname = tcase->name, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + streamh = create.out.file.handle; + + ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase, + mem_ctx, baseh, streamh, T_OVERWRITE); + torture_assert_goto(tctx, ret, ret, done, "test failed\n"); + + /* + * Subtest: setinfo EOF 0 + */ + torture_comment(tctx, "Subtest: T_EOF\n"); + + status = smb2_util_unlink(tree, BASEDIR "\\file"); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + + status = torture_smb2_testfile_access(tree, BASEDIR "\\file", + &baseh, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = torture_smb2_testfile_access(tree, tcase->name, &streamh, + tcase->access); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = smb2_util_write(tree, streamh, tcase->write_data, 0, + tcase->write_size); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_open failed\n"); + + sfinfo = (union smb_setfileinfo) { + .end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION, + .end_of_file_info.in.file.handle = streamh, + .end_of_file_info.in.size = 0, + }; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set eof 0 failed\n"); + + ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase, + mem_ctx, baseh, streamh, T_EOF); + torture_assert_goto(tctx, ret, ret, done, "test failed\n"); + + /* + * Subtest: delete-on-close + */ + torture_comment(tctx, "Subtest: T_DOC\n"); + + status = smb2_util_unlink(tree, BASEDIR "\\file"); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + + status = torture_smb2_testfile_access(tree, BASEDIR "\\file", + &baseh, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = torture_smb2_testfile_access(tree, tcase->name, &streamh, + tcase->access); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile_access failed\n"); + + status = smb2_util_write(tree, streamh, tcase->write_data, 0, + tcase->write_size); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_open failed\n"); + + sfinfo = (union smb_setfileinfo) { + .disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFORMATION, + .disposition_info.in.file.handle = streamh, + .disposition_info.in.delete_on_close = true, + }; + status = smb2_setinfo_file(tree, &sfinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "set eof 0 failed\n"); + + ret = test_empty_stream_do_checks(tctx, tree, tree2, tcase, + mem_ctx, baseh, streamh, + T_DOC); + torture_assert_goto(tctx, ret, ret, done, "test failed\n"); + + ret = true; + +done: + smb2_util_close(tree, baseh); + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool test_empty_stream(struct torture_context *tctx, + struct smb2_tree *tree) +{ + struct smb2_tree *tree2 = NULL; + struct tcase *tcase = NULL; + const char *fname = BASEDIR "\\file"; + struct smb2_handle h1; + bool ret = true; + NTSTATUS status; + AfpInfo ai = (AfpInfo) { + .afpi_Signature = AFP_Signature, + .afpi_Version = AFP_Version, + .afpi_BackupTime = AFP_BackupTime, + .afpi_FinderInfo = "FOO BAR ", + }; + char *ai_blob = torture_afpinfo_pack(tctx, &ai); + struct tcase tcase_afpinfo_ro = (struct tcase) { + .name = BASEDIR "\\file" AFPINFO_STREAM, + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, + .create = { + .size = 60, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + }; + struct tcase tcase_afpinfo_rw = (struct tcase) { + .name = BASEDIR "\\file" AFPINFO_STREAM, + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE, + .write_data = ai_blob, + .write_size = AFP_INFO_SIZE, + .create = { + .size = 60, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .write = { + .size = 60, + .initial_status = NT_STATUS_OK, + .final_status = NT_STATUS_OK, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 2, + .streams_open_handle = {"::$DATA", AFPINFO_STREAM}, + .streams_closed_handle = {"::$DATA", AFPINFO_STREAM}, + }, + .overwrite = { + .size = 60, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .eof = { + .size = 60, + .initial_status = NT_STATUS_OK, + .final_status = NT_STATUS_OK, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 2, + .streams_open_handle = {"::$DATA", AFPINFO_STREAM}, + .streams_closed_handle = {"::$DATA", AFPINFO_STREAM}, + }, + .doc = { + .size = 60, + .initial_status = NT_STATUS_DELETE_PENDING, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA", AFPINFO_STREAM}, + .streams_closed_handle = {"::$DATA"}, + }, + }; + + struct tcase tcase_afpresource_ro = (struct tcase) { + .name = BASEDIR "\\file" AFPRESOURCE_STREAM, + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, + .create = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + }; + struct tcase tcase_afpresource_rw = (struct tcase) { + .name = BASEDIR "\\file" AFPRESOURCE_STREAM, + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE, + .write_data = "foo", + .write_size = 3, + .create = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .write = { + .size = 3, + .initial_status = NT_STATUS_OK, + .final_status = NT_STATUS_OK, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 2, + .streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM}, + .streams_closed_handle = {"::$DATA", AFPRESOURCE_STREAM}, + }, + .overwrite = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .eof = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .doc = { + .size = 3, + .initial_status = NT_STATUS_DELETE_PENDING, + .final_status = NT_STATUS_OK, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 2, + .streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM}, + .streams_closed_handle = {"::$DATA", AFPRESOURCE_STREAM}, + }, + }; + + struct tcase tcase_foo_ro = (struct tcase) { + .name = BASEDIR "\\file:foo", + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE, + .write_data = "foo", + .write_size = 3, + .create = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + }; + + struct tcase tcase_foo_rw = (struct tcase) { + .name = BASEDIR "\\file:foo", + .access = SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_DATA|SEC_STD_DELETE, + .write_data = "foo", + .write_size = 3, + .create = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .write = { + .size = 3, + .initial_status = NT_STATUS_OK, + .final_status = NT_STATUS_OK, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 2, + .streams_open_handle = {"::$DATA", ":foo:$DATA"}, + .streams_closed_handle = {"::$DATA", ":foo:$DATA"}, + }, + .overwrite = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .eof = { + .size = 0, + .initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 1, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + .doc = { + .size = 3, + .initial_status = NT_STATUS_DELETE_PENDING, + .final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, + .num_streams_open_handle = 2, + .num_streams_closed_handle = 1, + .streams_open_handle = {"::$DATA", ":foo:$DATA"}, + .streams_closed_handle = {"::$DATA"}, + }, + }; + + struct tcase tcases[] = { + tcase_afpinfo_ro, + tcase_afpinfo_rw, + tcase_afpresource_ro, + tcase_afpresource_rw, + tcase_foo_ro, + tcase_foo_rw, + {0} + }; + + ret = torture_smb2_connection(tctx, &tree2); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_smb2_connection failed\n"); + + ret = enable_aapl(tctx, tree); + torture_assert(tctx, ret == true, "enable_aapl failed\n"); + + ret = enable_aapl(tctx, tree2); + torture_assert(tctx, ret == true, "enable_aapl failed\n"); + + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + + for (tcase = &tcases[0]; tcase->name != NULL; tcase++) { + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = test_empty_stream_do_one(tctx, tree, tree2, tcase); + torture_assert_goto(tctx, ret == true, ret, done, + "subtest failed\n"); + + status = smb2_util_unlink(tree, fname); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_unlink failed\n"); + } + +done: + smb2_deltree(tree, BASEDIR); + TALLOC_FREE(tree2); + return ret; +} + +/* +------------------------------------------------------------------------------- +MagicNumber: 00051607 : AppleDouble +Version : 00020000 : Version 2 +Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X +Num. of ent: 0002 : 2 + +------------------------------------------------------------------------------- +Entry ID : 00000009 : Finder Info +Offset : 00000032 : 50 +Length : 00000EB0 : 3760 + +-DInfo-----: +Rect top : 0000 : 0 +Rect left : 0000 : 0 +Rect bottom: 0000 : 0 +Rect right : 0000 : 0 +isAlias : 0 +Invisible : 0 +hasBundle : 0 +nameLocked : 0 +Stationery : 0 +CustomIcon : 0 +Reserved : 0 +Inited : 1 +NoINITS : 0 +Shared : 0 +SwitchLaunc: 0 +Hidden Ext : 0 +color : 000 : none +isOnDesk : 0 +Location v : 0000 : 0 +Location h : 0000 : 0 +View : 0000 : .. + +-DXInfo----: +Scroll v : 0000 : 0 +Scroll h : 0000 : 0 +Rsvd|OpnChn: 00000000 : 0 +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 +Comment : 0000 : .. +PutAway : 00000000 : 0 + +-EA--------: +pad : 0000 : .. +magic : 41545452 : ATTR +debug_tag : 0081714C : 8483148 +total_size : 00000EE2 : 3810 +data_start : 00000098 : 152 +data_length: 00000039 : 57 +reserved[0]: 00000000 : .... +reserved[1]: 00000000 : .... +reserved[2]: 00000000 : .... +flags : 0000 : .. +num_attrs : 0001 : 1 +-EA ENTRY--: +offset : 00000098 : 152 +length : 00000039 : 57 +flags : 0000 : .. +namelen : 15 : 21 +-EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 63 6F 6D 2E 61 70 70 6C 65 2E 71 75 61 72 61 6E : com.apple.quaran +00000010 : 74 69 6E 65 00 : tine. +-EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 30 30 38 31 3B 36 32 65 61 33 37 66 64 3B 43 68 : 0081;62ea37fd;Ch +00000010 : 72 6F 6D 65 3B 42 35 39 46 42 39 45 44 2D 35 41 : rome;B59FB9ED-5A +00000020 : 32 39 2D 34 45 35 42 2D 38 35 36 43 2D 37 45 44 : 29-4E5B-856C-7ED +00000030 : 30 45 46 45 41 37 30 41 43 : 0EFEA70AC + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 : ................ +00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000020 : 00 00 41 54 54 52 00 81 71 4C 00 00 0E E2 00 00 : ..ATTR..qL...... +00000030 : 00 98 00 00 00 39 00 00 00 00 00 00 00 00 00 00 : .....9.......... +00000040 : 00 00 00 00 00 01 00 00 00 98 00 00 00 39 00 00 : .............9.. +00000050 : 15 63 6F 6D 2E 61 70 70 6C 65 2E 71 75 61 72 61 : .com.apple.quara +00000060 : 6E 74 69 6E 65 00 30 30 38 31 3B 36 32 65 61 33 : ntine.0081;62ea3 +00000070 : 37 66 64 3B 43 68 72 6F 6D 65 3B 42 35 39 46 42 : 7fd;Chrome;B59FB +00000080 : 39 45 44 2D 35 41 32 39 2D 34 45 35 42 2D 38 35 : 9ED-5A29-4E5B-85 +00000090 : 36 43 2D 37 45 44 30 45 46 45 41 37 30 41 43 00 : 6C-7ED0EFEA70AC. +000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000100 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000110 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000120 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000130 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000140 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000150 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000160 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000170 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000180 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000190 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000001F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000200 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000210 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000220 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000230 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000240 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000250 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000260 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000270 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000280 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000290 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000002F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000300 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000310 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000320 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000330 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000340 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000350 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000360 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000370 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000380 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000390 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000003F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000400 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000410 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000420 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000430 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000440 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000450 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000460 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000470 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000480 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000490 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000004F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000500 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000510 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000520 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000530 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000540 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000550 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000560 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000570 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000580 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000590 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000005F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000600 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000610 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000620 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000630 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000640 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000650 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000660 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000670 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000680 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000690 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000006F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000700 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000710 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000720 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000730 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000740 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000750 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000760 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000770 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000780 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000790 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000007F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000800 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000810 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000820 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000830 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000840 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000850 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000860 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000870 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000880 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000890 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000008F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000900 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000910 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000920 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000930 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000940 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000950 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000960 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000970 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000980 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000990 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000009F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000A90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000AF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000B90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000BF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000C90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000CF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000D90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DB0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DC0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DD0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DE0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000DF0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000E90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000EA0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + +------------------------------------------------------------------------------- +Entry ID : 00000002 : Resource Fork +Offset : 00000EE2 : 3810 +Length : 0000011E : 286 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000010 : 54 68 69 73 20 72 65 73 6F 75 72 63 65 20 66 6F : This resource fo +00000020 : 72 6B 20 69 6E 74 65 6E 74 69 6F 6E 61 6C 6C 79 : rk intentionally +00000030 : 20 6C 65 66 74 20 62 6C 61 6E 6B 20 20 20 00 00 : left blank .. +00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000080 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000090 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000A0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000B0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000C0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000D0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000E0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +000000F0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ +00000100 : 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 1E : ................ +00000110 : 00 00 00 00 00 00 00 00 00 1C 00 1E FF FF : .............. +*/ + +static char osx_adouble_dir_w_xattr[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x32, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x0e, 0xe2, 0x00, 0x00, + 0x01, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 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, 0x41, 0x54, 0x54, 0x52, + 0x00, 0x81, 0x71, 0x4c, 0x00, 0x00, 0x0e, 0xe2, + 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x39, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x39, + 0x00, 0x00, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, + 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x71, 0x75, 0x61, + 0x72, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x00, + 0x30, 0x30, 0x38, 0x31, 0x3b, 0x36, 0x32, 0x65, + 0x61, 0x33, 0x37, 0x66, 0x64, 0x3b, 0x43, 0x68, + 0x72, 0x6f, 0x6d, 0x65, 0x3b, 0x42, 0x35, 0x39, + 0x46, 0x42, 0x39, 0x45, 0x44, 0x2d, 0x35, 0x41, + 0x32, 0x39, 0x2d, 0x34, 0x45, 0x35, 0x42, 0x2d, + 0x38, 0x35, 0x36, 0x43, 0x2d, 0x37, 0x45, 0x44, + 0x30, 0x45, 0x46, 0x45, 0x41, 0x37, 0x30, 0x41, + 0x43, 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, + 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, 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, 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, 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, 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, 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, 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, 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, + 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, 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, 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, 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, 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, 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, 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, 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x54, 0x68, 0x69, 0x73, 0x20, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x6c, 0x79, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x20, + 0x62, 0x6c, 0x61, 0x6e, 0x6b, 0x20, 0x20, 0x20, + 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, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1e, 0xff, 0xff +}; + +static bool test_delete_trigger_convert_sharing_violation( + struct torture_context *tctx, + struct smb2_tree *tree1) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *dirname = BASEDIR "\\dir"; + const char *adname = BASEDIR "\\._dir"; + struct smb2_handle testdirh; + struct smb2_create create; + AfpInfo *info = NULL; + bool ret = true; + NTSTATUS status; + + smb2_deltree(tree1, BASEDIR); + + status = torture_smb2_testdir(tree1, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + smb2_util_close(tree1, testdirh); + + status = torture_smb2_testdir(tree1, dirname, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + smb2_util_close(tree1, testdirh); + + ret = torture_setup_file(tctx, tree1, adname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = write_stream(tree1, __location__, tctx, mem_ctx, + adname, NULL, 0, + sizeof(osx_adouble_dir_w_xattr), + osx_adouble_dir_w_xattr); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + /* + * 1) Create a non-empty AFP_AfpInfo stream + */ + + info = torture_afpinfo_new(mem_ctx); + torture_assert_goto(tctx, info != NULL, ret, done, "torture_afpinfo_new failed"); + + /* Set "Inited" flag (any other would do too) */ + info->afpi_FinderInfo[8] = 0x01; + + ret = torture_write_afpinfo(tree1, tctx, mem_ctx, dirname, info); + torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed"); + + ret = write_stream(tree1, __location__, tctx, mem_ctx, + adname, NULL, 0, + sizeof(osx_adouble_dir_w_xattr), + osx_adouble_dir_w_xattr); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + /* + * 2) Create a second stream + */ + + ret = write_stream(tree1, __location__, tctx, mem_ctx, + dirname, ":org.samba.boom", 0, + strlen("boom"), + "boom"); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + create = (struct smb2_create) { + .in.desired_access = SEC_STD_DELETE, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = dirname, + }; + + status = smb2_create(tree1, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + status = smb2_util_close(tree1, create.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed"); + +done: + smb2_deltree(tree1, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +/* + * Note: This test depends on "vfs objects = catia fruit streams_xattr". For + * some tests torture must be run on the host it tests and takes an additional + * argument with the local path to the share: + * "--option=torture:localdir=<SHAREPATH>". + * + * When running against an OS X SMB server add "--option=torture:osx=true" + */ +struct torture_suite *torture_vfs_fruit(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "fruit"); + + suite->description = talloc_strdup(suite, "vfs_fruit tests"); + + torture_suite_add_1smb2_test(suite, "copyfile", test_copyfile); + torture_suite_add_1smb2_test(suite, "read metadata", test_read_afpinfo); + torture_suite_add_1smb2_test(suite, "write metadata", test_write_atalk_metadata); + torture_suite_add_1smb2_test(suite, "resource fork IO", test_write_atalk_rfork_io); + torture_suite_add_1smb2_test(suite, "SMB2/CREATE context AAPL", test_aapl); + torture_suite_add_1smb2_test(suite, "stream names", test_stream_names); + torture_suite_add_1smb2_test(suite, "truncate resource fork to 0 bytes", test_rfork_truncate); + torture_suite_add_1smb2_test(suite, "opening and creating resource fork", test_rfork_create); + torture_suite_add_1smb2_test(suite, "fsync_resource_fork", test_rfork_fsync); + torture_suite_add_1smb2_test(suite, "rename_dir_openfile", test_rename_dir_openfile); + torture_suite_add_1smb2_test(suite, "File without AFP_AfpInfo", test_afpinfo_enoent); + torture_suite_add_1smb2_test(suite, "create delete-on-close AFP_AfpInfo", test_create_delete_on_close); + torture_suite_add_1smb2_test(suite, "setinfo delete-on-close AFP_AfpInfo", test_setinfo_delete_on_close); + torture_suite_add_1smb2_test(suite, "setinfo eof AFP_AfpInfo", test_setinfo_eof); + torture_suite_add_1smb2_test(suite, "delete AFP_AfpInfo by writing all 0", test_afpinfo_all0); + torture_suite_add_1smb2_test(suite, "create delete-on-close AFP_AfpResource", test_create_delete_on_close_resource); + torture_suite_add_1smb2_test(suite, "setinfo delete-on-close AFP_AfpResource", test_setinfo_delete_on_close_resource); + torture_suite_add_1smb2_test(suite, "setinfo eof AFP_AfpResource", test_setinfo_eof_resource); + torture_suite_add_1smb2_test(suite, "setinfo eof stream", test_setinfo_stream_eof); + torture_suite_add_1smb2_test(suite, "null afpinfo", test_null_afpinfo); + torture_suite_add_1smb2_test(suite, "delete", test_delete_file_with_rfork); + torture_suite_add_1smb2_test(suite, "read open rsrc after rename", test_rename_and_read_rsrc); + torture_suite_add_1smb2_test(suite, "readdir_attr with names with illegal ntfs characters", test_readdir_attr_illegal_ntfs); + torture_suite_add_2ns_smb2_test(suite, "invalid AFP_AfpInfo", test_invalid_afpinfo); + torture_suite_add_1smb2_test(suite, "creating rsrc with read-only access", test_rfork_create_ro); + torture_suite_add_1smb2_test(suite, "copy-chunk streams", test_copy_chunk_streams); + torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion", test_adouble_conversion); + torture_suite_add_1smb2_test(suite, "NFS ACE entries", test_nfs_aces); + torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion without embedded xattr", test_adouble_conversion_wo_xattr); + torture_suite_add_1smb2_test(suite, "empty_stream", test_empty_stream); + torture_suite_add_1smb2_test(suite, "writing_afpinfo", test_writing_afpinfo); + torture_suite_add_1smb2_test(suite, "delete_trigger_convert_sharing_violation", test_delete_trigger_convert_sharing_violation); + + return suite; +} + +static bool test_stream_names_local(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + NTSTATUS status; + struct smb2_create create; + struct smb2_handle h; + const char *fname = BASEDIR "\\stream_names.txt"; + const char *sname1; + bool ret; + /* UTF8 private use are starts at 0xef 0x80 0x80 (0xf000) */ + const char *streams[] = { + ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */ + ":bar" "\xef\x80\xa2" "baz:$DATA", /* "bar:baz:$DATA" */ + "::$DATA" + }; + const char *localdir = NULL; + + localdir = torture_setting_string(tctx, "localdir", NULL); + if (localdir == NULL) { + torture_skip(tctx, "Need localdir for test"); + } + + sname1 = talloc_asprintf(mem_ctx, "%s%s", fname, streams[0]); + + /* clean slate ...*/ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + torture_comment(tctx, "(%s) testing stream names\n", __location__); + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_WRITE_DATA; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + create.in.create_disposition = NTCREATEX_DISP_CREATE; + create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + create.in.fname = sname1; + + status = smb2_create(tree, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smb2_util_write(tree, create.out.file.handle, "foo", 0, 3); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + smb2_util_close(tree, create.out.file.handle); + + ret = torture_setup_local_xattr(tctx, "localdir", BASEDIR "/stream_names.txt", + "user.DosStream.bar:baz:$DATA", + "data", strlen("data")); + CHECK_VALUE(ret, true); + + ret = check_stream_list(tree, tctx, fname, 3, streams, false); + CHECK_VALUE(ret, true); + +done: + status = smb2_util_unlink(tree, fname); + smb2_deltree(tree, BASEDIR); + talloc_free(mem_ctx); + + return ret; +} + +static bool test_fruit_locking_conflict(struct torture_context *tctx, + struct smb2_tree *tree, + struct smb2_tree *tree2) +{ + TALLOC_CTX *mem_ctx; + struct smb2_create create; + struct smb2_handle h; + struct smb2_lock lck; + struct smb2_lock_element el; + const char *fname = BASEDIR "\\locking_conflict.txt"; + NTSTATUS status; + bool ret = false; + + mem_ctx = talloc_new(tctx); + torture_assert_not_null(tctx, mem_ctx, "talloc_new failed"); + + /* clean slate ...*/ + smb2_util_unlink(tree, fname); + smb2_deltree(tree, fname); + smb2_deltree(tree, BASEDIR); + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_FILE_READ, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE, + .in.create_disposition = NTCREATEX_DISP_CREATE, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = fname, + }; + + status = smb2_create(tree, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_OK); + h = create.out.file.handle; + + /* Add AD_FILELOCK_RSRC_DENY_WR lock. */ + el = (struct smb2_lock_element) { + .offset = 0xfffffffffffffffc, + .length = 1, + .flags = SMB2_LOCK_FLAG_EXCLUSIVE, + }; + lck = (struct smb2_lock) { + .in.lock_count = 1, + .in.file.handle = h, + .in.locks = &el, + }; + + /* + * Lock up to and including: + * AD_FILELOCK_OPEN_WR + * AD_FILELOCK_OPEN_RD + * This is designed to cause a NetAtalk + * locking conflict on the next open, + * even though the share modes are + * compatible. + */ + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + + el = (struct smb2_lock_element) { + .offset = 0, + .length = 0x7ffffffffffffff7, + .flags = SMB2_LOCK_FLAG_EXCLUSIVE, + }; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + + create = (struct smb2_create) { + .in.desired_access = + SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = fname, + }; + + /* + * Open on the second tree - ensure we are + * emulating trying to access with a NetATalk + * process with an existing open/deny mode. + */ + status = smb2_create(tree2, mem_ctx, &create); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + + { + struct smb2_close cl = { + .level = RAW_CLOSE_SMB2, + .in.file.handle = h, + }; + smb2_close(tree, &cl); + } + + ret = true; +done: + return ret; +} + +struct torture_suite *torture_vfs_fruit_netatalk(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "fruit_netatalk"); + + suite->description = talloc_strdup(suite, "vfs_fruit tests for Netatalk interop that require fruit:metadata=netatalk"); + + torture_suite_add_1smb2_test(suite, "read netatalk metadata", test_read_netatalk_metadata); + torture_suite_add_1smb2_test(suite, "stream names with locally created xattr", test_stream_names_local); + torture_suite_add_2smb2_test( + suite, "locking conflict", test_fruit_locking_conflict); + + return suite; +} + +struct torture_suite *torture_vfs_fruit_file_id(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = + torture_suite_create(ctx, "fruit_file_id"); + + suite->description = + talloc_strdup(suite, "vfs_fruit tests for on-disk file ID that " + "require fruit:zero_file_id=yes"); + + torture_suite_add_1smb2_test(suite, "zero file id if AAPL negotiated", + test_zero_file_id); + + return suite; +} + +static bool test_timemachine_volsize(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle h = {{0}}; + union smb_fsinfo fsinfo; + NTSTATUS status; + bool ok = true; + const char *info_plist = + "<dict>\n" + " <key>band-size</key>\n" + " <integer>8192</integer>\n" + "</dict>\n"; + + smb2_deltree(tree, "test.sparsebundle"); + + ok = enable_aapl(tctx, tree); + torture_assert_goto(tctx, ok, ok, done, "enable_aapl failed"); + + status = smb2_util_mkdir(tree, "test.sparsebundle"); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "smb2_util_mkdir\n"); + + ok = write_stream(tree, __location__, tctx, mem_ctx, + "test.sparsebundle/Info.plist", NULL, + 0, strlen(info_plist), info_plist); + torture_assert_goto(tctx, ok, ok, done, "write_stream failed\n"); + + status = smb2_util_mkdir(tree, "test.sparsebundle/bands"); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "smb2_util_mkdir\n"); + + ok = torture_setup_file(tctx, tree, "test.sparsebundle/bands/1", false); + torture_assert_goto(tctx, ok, ok, done, "torture_setup_file failed\n"); + + ok = torture_setup_file(tctx, tree, "test.sparsebundle/bands/2", false); + torture_assert_goto(tctx, ok, ok, done, "torture_setup_file failed\n"); + + status = smb2_util_roothandle(tree, &h); + torture_assert_ntstatus_ok(tctx, status, "Unable to create root handle"); + + ZERO_STRUCT(fsinfo); + fsinfo.generic.level = RAW_QFS_SIZE_INFORMATION; + fsinfo.generic.handle = h; + + status = smb2_getinfo_fs(tree, tree, &fsinfo); + torture_assert_ntstatus_ok(tctx, status, "smb2_getinfo_fs failed"); + + torture_comment(tctx, "sectors_per_unit: %" PRIu32"\n" + "bytes_per_sector: %" PRIu32"\n" + "total_alloc_units: %" PRIu64"\n" + "avail_alloc_units: %" PRIu64"\n", + fsinfo.size_info.out.sectors_per_unit, + fsinfo.size_info.out.bytes_per_sector, + fsinfo.size_info.out.total_alloc_units, + fsinfo.size_info.out.avail_alloc_units); + + /* + * Let me explain the numbers: + * + * - the share is set to "fruit:time machine max size = 32K" + * - we've faked a bandsize of 8 K in the Info.plist file + * - we've created two bands files + * - one allocation unit is made of two sectors with 512 B each + * => we've consumed 16 allocation units, there should be 16 free + */ + + torture_assert_goto(tctx, fsinfo.size_info.out.sectors_per_unit == 2, + ok, done, "Bad sectors_per_unit"); + + torture_assert_goto(tctx, fsinfo.size_info.out.bytes_per_sector == 512, + ok, done, "Bad bytes_per_sector"); + + torture_assert_goto(tctx, fsinfo.size_info.out.total_alloc_units == 32, + ok, done, "Bad total_alloc_units"); + + torture_assert_goto(tctx, fsinfo.size_info.out.avail_alloc_units == 16, + ok, done, "Bad avail_alloc_units"); + +done: + if (!smb2_util_handle_empty(h)) { + smb2_util_close(tree, h); + } + smb2_deltree(tree, "test.sparsebundle"); + talloc_free(mem_ctx); + return ok; +} + +struct torture_suite *torture_vfs_fruit_timemachine(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "fruit_timemachine"); + + suite->description = talloc_strdup( + suite, "vfs_fruit tests for TimeMachine"); + + torture_suite_add_1smb2_test(suite, "Timemachine-volsize", + test_timemachine_volsize); + + return suite; +} + +static bool test_convert_xattr_and_empty_rfork_then_delete( + struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\test_adouble_conversion"; + const char *adname = BASEDIR "/._test_adouble_conversion"; + const char *rfork = BASEDIR "\\test_adouble_conversion" AFPRESOURCE_STREAM_NAME; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + const char *streams[] = { + "::$DATA", + AFPINFO_STREAM, + ":com.apple.metadata" "\xef\x80\xa2" "_kMDItemUserTags:$DATA", + ":foo" "\xef\x80\xa2" "bar:$DATA", /* "foo:bar:$DATA" */ + }; + struct smb2_create create; + struct smb2_find find; + unsigned int count; + union smb_search_data *d; + bool delete_empty_adfiles; + int expected_num_files; + + delete_empty_adfiles = torture_setting_bool(tctx, + "delete_empty_adfiles", + false); + + smb2_deltree(tree1, BASEDIR); + + status = torture_smb2_testdir(tree1, BASEDIR, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + smb2_util_close(tree1, testdirh); + + ret = torture_setup_file(tctx, tree1, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = torture_setup_file(tctx, tree1, adname, false); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_setup_file failed\n"); + + ret = write_stream(tree1, __location__, tctx, mem_ctx, + adname, NULL, + 0, sizeof(osx_adouble_w_xattr), osx_adouble_w_xattr); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + ret = enable_aapl(tctx, tree2); + torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed"); + + /* + * Issue a smb2_find(), this triggers the server-side conversion + */ + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_DIR_READ, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = BASEDIR, + }; + + status = smb2_create(tree2, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + find = (struct smb2_find) { + .in.file.handle = create.out.file.handle, + .in.pattern = "*", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + }; + + status = smb2_find_level(tree2, tree2, &find, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + status = smb2_util_close(tree2, create.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed"); + + /* + * Check number of streams + */ + + ret = check_stream_list(tree2, tctx, fname, 4, streams, false); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream_list"); + + /* + * Check Resource Fork is gone + */ + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = rfork, + }; + + status = smb2_create(tree2, mem_ctx, &create); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ret, done, "Bad smb2_create return\n"); + + /* + * Check xattr data has been migrated from the AppleDouble file to + * streams. + */ + + ret = check_stream(tree2, __location__, tctx, mem_ctx, + fname, AFPINFO_STREAM, + 0, 60, 16, 8, "TESTSLOW"); + torture_assert_goto(tctx, ret == true, ret, done, + "check AFPINFO_STREAM failed\n"); + + ret = check_stream(tree2, __location__, tctx, mem_ctx, + fname, ":foo" "\xef\x80\xa2" "bar", /* foo:bar */ + 0, 3, 0, 3, "baz"); + torture_assert_goto(tctx, ret == true, ret, done, + "check foo stream failed\n"); + + /* + * Now check number of files. If delete_empty_adfiles is set, the + * AppleDouble files should have been deleted. + */ + + create = (struct smb2_create) { + .in.desired_access = SEC_RIGHTS_DIR_READ, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.share_access = NTCREATEX_SHARE_ACCESS_READ, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS, + .in.fname = BASEDIR, + }; + + status = smb2_create(tree2, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + find = (struct smb2_find) { + .in.file.handle = create.out.file.handle, + .in.pattern = "*", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + }; + + status = smb2_find_level(tree2, tree2, &find, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + status = smb2_util_close(tree2, create.out.file.handle); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_close failed"); + + if (delete_empty_adfiles) { + expected_num_files = 3; + } else { + expected_num_files = 4; + } + torture_assert_int_equal_goto(tctx, count, expected_num_files, ret, done, + "Wrong number of files\n"); + +done: + smb2_deltree(tree1, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + +struct torture_suite *torture_vfs_fruit_conversion(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "fruit_conversion"); + + suite->description = talloc_strdup( + suite, "vfs_fruit conversion tests"); + + torture_suite_add_2ns_smb2_test( + suite, "convert_xattr_and_empty_rfork_then_delete", + test_convert_xattr_and_empty_rfork_then_delete); + + return suite; +} + +/* + * The buf below contains the following AppleDouble encoded data: + * + * ----------------------------------------------------------------------------- + * MagicNumber: 00051607 : AppleDouble + * Version : 00020000 : Version 2 + * Filler : 4D 61 63 20 4F 53 20 58 20 20 20 20 20 20 20 20 : Mac OS X + * Num. of ent: 0002 : 2 + * + * ----------------------------------------------------------------------------- + * Entry ID : 00000002 : Resource Fork + * Offset : 0000009A : 154 + * Length : 00000004 : 4 + * + * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) + * 00000000 : 62 61 72 00 : bar. + * + * ----------------------------------------------------------------------------- + * Entry ID : 00000009 : Finder Info + * Offset : 00000032 : 50 + * Length : 00000068 : 104 + * + * -FInfo-----: + * Type : 464F4F20 : FOO + * Creator : 42415220 : BAR + * isAlias : 0 + * Invisible : 0 + * 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 + * + * -EA--------: + * pad : 0000 : + * magic : 41545452 : ATTR + * debug_tag : 00000000 : 0 + * total_size : 0000009A : 154 + * data_start : 00000096 : 150 + * data_length: 00000004 : 4 + * reserved[0]: 00000000 : .... + * reserved[1]: 00000000 : .... + * reserved[2]: 00000000 : .... + * flags : 0000 : .. + * num_attrs : 0001 : 1 + * -EA ENTRY--: + * offset : 00000096 : 150 + * length : 00000004 : 4 + * flags : 0000 : .. + * namelen : 13 : 19 + * -EA NAME---: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) + * 00000000 : 6F 72 67 2E 73 61 6D 62 61 EF 80 A2 77 6F 6F 68 : org.samba...wooh + * 00000010 : 6F 6F 00 : oo. + * -EA VALUE--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) + * 00000000 : 62 61 72 00 : bar. + * + * -RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) + * 00000000 : 46 4F 4F 20 42 41 52 20 00 00 00 00 00 00 00 00 : FOO BAR ........ + * 00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000020 : 00 00 41 54 54 52 00 00 00 00 00 00 00 9A 00 00 : baATTR.......... + * 00000030 : 00 96 00 00 00 04 00 00 00 00 00 00 00 00 00 00 : ................ + * 00000040 : 00 00 00 00 00 01 00 00 00 96 00 00 00 04 00 00 : ................ + * 00000050 : 13 6F 72 67 2E 73 61 6D 62 61 EF 80 A2 77 6F 6F : .org.samba...woo + * 00000060 : 68 6F 6F 00 62 61 72 00 : hoo.bar. + * + * It was created with: + * + * $ hexdump -ve '"\t" 7/1 "0x%02x, " 1/1 " 0x%02x," "\n"' + */ +static char unconvert_adfile_data[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, + 0x00, 0x66, 0x46, 0x4f, 0x4f, 0x20, 0x42, 0x41, + 0x52, 0x20, 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, 0x41, 0x54, 0x54, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x11, 0x6f, 0x72, 0x67, 0x2e, 0x73, + 0x61, 0x6d, 0x62, 0x61, 0x3a, 0x77, 0x6f, 0x6f, + 0x68, 0x6f, 0x6f, 0x00, 0x62, 0x61, 0x72, 0x00, + 0x62, 0x61, 0x72, 0x00 +}; + +static bool test_unconvert(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + const char *fname = BASEDIR "\\unconvert"; + const char *adname = BASEDIR "\\._unconvert"; + const char *net = NULL; + const char *share = NULL; + AfpInfo *afpi = NULL; + char *cmd = NULL; + struct smb2_handle h1; + union smb_fileinfo finfo; + size_t adsize; + NTSTATUS status; + int result; + bool ret = true; + + torture_assert_not_null_goto(tctx, tree2, ret, done, + "Need a second share without fruit\n"); + + net = torture_setting_string(tctx, "net", NULL); + torture_assert_not_null_goto(tctx, net, ret, done, + "Need path to 'net'"); + + share = torture_setting_string(tctx, "sharename", NULL); + torture_assert_not_null_goto(tctx, share, ret, done, + "Need sharename"); + + torture_comment(tctx, "Testing unconvert\n"); + + smb2_deltree(tree1, BASEDIR); + + status = torture_smb2_testdir(tree1, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree1, h1); + + ret = torture_setup_file(tctx, tree1, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file"); + + afpi = torture_afpinfo_new(tctx); + torture_assert_not_null_goto(tctx, afpi, ret, done, + "torture_afpinfo_new failed\n"); + + memcpy(afpi->afpi_FinderInfo, "FOO BAR ", 8); + + ret = torture_write_afpinfo(tree1, tctx, tctx, fname, afpi); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_write_afpinfo failed\n"); + + ret = write_stream(tree1, __location__, tctx, tctx, + fname, + /* + * \xef\x80\xa2 is ':' mapped to Unicoe private range + */ + ":org.samba" "\xef\x80\xa2" "woohoo", + 0, 4, "bar"); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + ret = write_stream(tree1, __location__, tctx, tctx, + fname, AFPRESOURCE_STREAM_NAME, + 0, 4, "bar"); + torture_assert_goto(tctx, ret == true, ret, done, + "write_stream failed\n"); + + cmd = talloc_asprintf(tctx, + "%s --recursive vfs stream2adouble %s %s/", + net, + share, + BASEDIR); + torture_assert_not_null_goto(tctx, cmd, ret, done, + "talloc_asprintf failed\n"); + + torture_comment(tctx, "cmd: %s\n", cmd); + + result = system(cmd); + torture_assert_int_equal_goto(tctx, result, 0, ret, done, + "command failed\n"); + + status = torture_smb2_testfile(tree2, adname, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testfile failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree2, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree2, h1); + + adsize = finfo.all_info.out.size; + torture_assert_int_equal_goto(tctx, adsize, + sizeof(unconvert_adfile_data), + ret, done, "wrong size\n"); + + ret = check_stream(tree2, __location__, tctx, tctx, + adname, "", 0, adsize, 0, adsize, + unconvert_adfile_data); + torture_assert_goto(tctx, ret == true, ret, done, + "check_stream failed\n"); + +done: +// smb2_deltree(tree1, BASEDIR); + return ret; +} + +struct torture_suite *torture_vfs_fruit_unfruit(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "unfruit"); + + suite->description = talloc_strdup( + suite, "test converting back to AppleDouble"); + + torture_suite_add_2ns_smb2_test(suite, + "unconvert", + test_unconvert); + + return suite; +} + +/* + * Write an invalid AFP_AfpInfo stream header + */ +bool test_fruit_validate_afpinfo(struct torture_context *tctx, + struct smb2_tree *tree) +{ + bool expect_invalid_param = torture_setting_bool(tctx, "validate_afpinfo", true); + const char *fname = "test_fruit_validate_afpinfo"; + const char *sname = "test_fruit_validate_afpinfo" AFPINFO_STREAM_NAME; + struct smb2_handle handle; + AfpInfo *afpinfo = NULL; + char *afpinfo_buf = NULL; + uint8_t valbuf[8]; + NTSTATUS status; + bool ret = true; + + torture_comment(tctx, "Checking create of AfpInfo stream\n"); + + smb2_util_unlink(tree, fname); + + ret = torture_setup_file(tctx, tree, fname, false); + torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed"); + + afpinfo = torture_afpinfo_new(tctx); + torture_assert_not_null_goto(tctx, afpinfo, ret, done, + "torture_afpinfo_new failed\n"); + + memcpy(afpinfo->afpi_FinderInfo, "FOO BAR ", 8); + + ret = torture_write_afpinfo(tree, tctx, tctx, fname, afpinfo); + torture_assert_goto(tctx, ret == true, ret, done, + "torture_write_afpinfo failed\n"); + + afpinfo_buf = talloc_zero_size(tctx, 60); + torture_assert_goto(tctx, afpinfo_buf != NULL, ret, done, + "torture_afpinfo_new failed"); + memcpy(afpinfo_buf + 16, "FOO ", 4); + + status = torture_smb2_testfile_access( + tree, sname, &handle, SEC_FILE_ALL); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_create failed\n"); + + status = smb2_util_write(tree, handle, afpinfo_buf, 0, AFP_INFO_SIZE); + if (expect_invalid_param) { + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_INVALID_PARAMETER, ret, done, + "write didn't fail as expected\n"); + } else { + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed"); + } + + smb2_util_close(tree, handle); + + /* + * Verify the server fixed the header + */ + PUSH_BE_U32(valbuf, 0, AFP_Signature); + PUSH_BE_U32(valbuf + 4, 0, AFP_Version); + ret = check_stream(tree, __location__, tctx, tctx, fname, + AFPINFO_STREAM, 0, 60, 0, 8, (char *)valbuf); + torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed"); + +done: + smb2_util_unlink(tree, fname); + return ret; +} diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c new file mode 100644 index 0000000..3d402ee --- /dev/null +++ b/source4/torture/vfs/vfs.c @@ -0,0 +1,123 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Ralph Boehme 2014 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "libcli/libcli.h" +#include "../lib/util/dlinklist.h" + +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "lib/cmdline/cmdline.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" + +#include "torture/util.h" +#include "torture/smbtorture.h" +#include "torture/vfs/proto.h" +#include "torture/smb2/proto.h" + +static bool wrap_2ns_smb2_test(struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *); + bool ok; + + struct smb2_tree *tree1 = NULL; + struct smb2_tree *tree2 = NULL; + TALLOC_CTX *mem_ctx = talloc_new(torture_ctx); + + if (!torture_smb2_connection(torture_ctx, &tree1)) { + torture_fail(torture_ctx, + "Establishing SMB2 connection failed\n"); + return false; + } + + /* + * This is a trick: + * The test might close the connection. If we steal the tree context + * before that and free the parent instead of tree directly, we avoid + * a double free error. + */ + talloc_steal(mem_ctx, tree1); + + ok = torture_smb2_con_sopt(torture_ctx, "share2", &tree2); + if (ok) { + talloc_steal(mem_ctx, tree2); + } + + fn = test->fn; + + ok = fn(torture_ctx, tree1, tree2); + + /* the test may already have closed some of the connections */ + talloc_free(mem_ctx); + + return ok; +} + +/* + * Run a test with 2 connected trees, the default share and another + * taken from option strings "torture:share2" + */ +struct torture_test *torture_suite_add_2ns_smb2_test(struct torture_suite *suite, + const char *name, + bool (*run)(struct torture_context *, + struct smb2_tree *, + struct smb2_tree *)) +{ + struct torture_test *test; + struct torture_tcase *tcase; + + tcase = torture_suite_add_tcase(suite, name); + + test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_2ns_smb2_test; + test->fn = run; + test->dangerous = false; + + DLIST_ADD_END(tcase->tests, test); + + return test; +} + +NTSTATUS torture_vfs_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create( + ctx, "vfs"); + + suite->description = talloc_strdup(suite, "VFS modules tests"); + + torture_suite_add_suite(suite, torture_vfs_fruit(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_netatalk(suite)); + torture_suite_add_suite(suite, torture_acl_xattr(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_file_id(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_timemachine(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_conversion(suite)); + torture_suite_add_suite(suite, torture_vfs_fruit_unfruit(suite)); + torture_suite_add_1smb2_test(suite, "fruit_validate_afpinfo", test_fruit_validate_afpinfo); + + torture_register_suite(ctx, suite); + + return NT_STATUS_OK; +} |