The Samba-Bugzilla – Attachment 14545 Details for
Bug 13646
File saving issues with vfs_fruit on samba >= 4.8.5
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Proposed patch for master backported to 4.8
v48-bug13646,13642,13649.patch (text/plain), 118.13 KB, created by
Ralph Böhme
on 2018-10-27 14:27:19 UTC
(
hide
)
Description:
Proposed patch for master backported to 4.8
Filename:
MIME Type:
Creator:
Ralph Böhme
Created:
2018-10-27 14:27:19 UTC
Size:
118.13 KB
patch
obsolete
>From 9ca83fc902e9f36cf19083a673f3d6e77df8bb54 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Fri, 19 Oct 2018 12:15:42 +0200 >Subject: [PATCH 01/43] vfs_fruit: remove check for number of xattrs from > ad_convert_xattr > >Turns out that there exist AppleDouble files with an extended FinderInfo >entry that includes the xattr marshall buffer, but the count of xattrs >in the buffer is just zero. > >We do want to discard this extended FinderInfo entry and convert it to a >simple fixed size FinderInfo entry, so remove the check. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13649 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 4 ---- > 1 file changed, 4 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 58ef3cc68d3..4b0e6e3d21f 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -1014,10 +1014,6 @@ static bool ad_convert_xattr(struct adouble *ad, > return true; > } > >- if (ad->adx_header.adx_num_attrs == 0) { >- return true; >- } >- > if (string_replace_cmaps == NULL) { > const char **mappings = NULL; > >-- >2.17.2 > > >From ad2cb8561c387f84ce3b4e41c9950e6d68b92b3e Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Tue, 2 Oct 2018 16:31:15 +0200 >Subject: [PATCH 02/43] docs:vfs_fruit: add > "wipe_intentionally_left_blank_rfork" option > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > docs-xml/manpages/vfs_fruit.8.xml | 14 ++++++++++++++ > 1 file changed, 14 insertions(+) > >diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml >index 25833038d96..0df5a7e5a79 100644 >--- a/docs-xml/manpages/vfs_fruit.8.xml >+++ b/docs-xml/manpages/vfs_fruit.8.xml >@@ -378,6 +378,20 @@ > </listitem> > </varlistentry> > >+ <varlistentry> >+ <term>fruit:wipe_intentionally_left_blank_rfork = yes | no</term> >+ <listitem> >+ <para>Whether to wipe Resource Fork data that matches the special >+ 286 bytes sized placeholder blob that macOS client create on >+ occasion. The blob contains a string <quote>This resource fork >+ intentionally left blank</quote>, the remaining bytes being mostly >+ zero. There being no one use of this data, it is probably safe to >+ discard it. When this option is enabled, this module truncates the >+ Resource Fork stream to 0 bytes.</para> >+ <para>The default is <emphasis>no</emphasis>.</para> >+ </listitem> >+ </varlistentry> >+ > </variablelist> > </refsect1> > >-- >2.17.2 > > >From 27122bdf3410ebcfdb51497909db4f728ba268ec Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 4 Oct 2018 18:22:31 +0200 >Subject: [PATCH 03/43] docs:vfs_fruit: add "delete_empty_adfiles" option > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > docs-xml/manpages/vfs_fruit.8.xml | 11 +++++++++++ > 1 file changed, 11 insertions(+) > >diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml >index 0df5a7e5a79..e4ca7bd1828 100644 >--- a/docs-xml/manpages/vfs_fruit.8.xml >+++ b/docs-xml/manpages/vfs_fruit.8.xml >@@ -392,6 +392,17 @@ > </listitem> > </varlistentry> > >+ <varlistentry> >+ <term>fruit:delete_empty_adfiles = yes | no</term> >+ <listitem> >+ <para>Whether to delete empty AppleDouble files. Empty means that >+ the resource fork entry in the AppleDouble files is of size 0, or >+ the size is exactly 286 bytes and the content matches a special >+ boilerplate resource fork created my macOS.</para> >+ <para>The default is <emphasis>no</emphasis>.</para> >+ </listitem> >+ </varlistentry> >+ > </variablelist> > </refsect1> > >-- >2.17.2 > > >From 5d0f3fda1ef64025b28e15e49eb021c3dcdc6a98 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 4 Oct 2018 13:47:20 +0200 >Subject: [PATCH 04/43] s3:selftest: list vfs testssuites one per line > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/selftest/tests.py | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > >diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py >index 069213e53c7..29b324e9b68 100755 >--- a/source3/selftest/tests.py >+++ b/source3/selftest/tests.py >@@ -416,7 +416,13 @@ nbt = ["nbt.dgram" ] > > libsmbclient = ["libsmbclient"] > >-vfs = ["vfs.fruit", "vfs.acl_xattr", "vfs.fruit_netatalk", "vfs.fruit_file_id", "vfs.fruit_timemachine"] >+vfs = [ >+ "vfs.fruit", >+ "vfs.acl_xattr", >+ "vfs.fruit_netatalk", >+ "vfs.fruit_file_id", >+ "vfs.fruit_timemachine", >+] > > tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs > >-- >2.17.2 > > >From 30496945f50e19672c75760446ad450ec4935b3b Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 4 Oct 2018 14:28:15 +0200 >Subject: [PATCH 05/43] s4:torture: add test for AppleDouble ResourceFork > conversion > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 2 + > selftest/target/Samba3.pm | 18 +++ > source3/selftest/tests.py | 4 + > source4/torture/vfs/fruit.c | 191 ++++++++++++++++++++++++++ > source4/torture/vfs/vfs.c | 1 + > 5 files changed, 216 insertions(+) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 6307e2b3404..f2a27040a8e 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,2 +1,4 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >+^samba3.vfs.fruit_conversion wipe_intentionally_left_blank_rfork.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\) >+^samba3.vfs.fruit_conversion delete_empty_adfiles.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\) >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index fdbf1fa9a9a..a5835d2f309 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -1957,6 +1957,24 @@ sub provision($$$$$$$$$) > fruit:time machine = yes > fruit:time machine max size = 32K > >+[vfs_fruit_wipe_intentionally_left_blank_rfork] >+ path = $shrdir >+ vfs objects = fruit streams_xattr acl_xattr xattr_tdb >+ fruit:resource = file >+ fruit:metadata = stream >+ fruit:wipe_intentionally_left_blank_rfork = true >+ fruit:delete_empty_adfiles = false >+ fruit:veto_appledouble = no >+ >+[vfs_fruit_delete_empty_adfiles] >+ path = $shrdir >+ vfs objects = fruit streams_xattr acl_xattr xattr_tdb >+ fruit:resource = file >+ fruit:metadata = stream >+ fruit:wipe_intentionally_left_blank_rfork = true >+ fruit:delete_empty_adfiles = true >+ fruit:veto_appledouble = no >+ > [badname-tmp] > path = $badnames_shrdir > guest ok = yes >diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py >index 29b324e9b68..ced19268611 100755 >--- a/source3/selftest/tests.py >+++ b/source3/selftest/tests.py >@@ -422,6 +422,7 @@ vfs = [ > "vfs.fruit_netatalk", > "vfs.fruit_file_id", > "vfs.fruit_timemachine", >+ "vfs.fruit_conversion", > ] > > tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs >@@ -532,6 +533,9 @@ tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap > plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_timemachine -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') > elif t == "vfs.fruit_file_id": > plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD') >+ elif t == "vfs.fruit_conversion": >+ plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:share2=vfs_fruit_wipe_intentionally_left_blank_rfork --option=torture:delete_empty_adfiles=false', 'wipe_intentionally_left_blank_rfork') >+ plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD --option=torture:share2=vfs_fruit_delete_empty_adfiles --option=torture:delete_empty_adfiles=true', 'delete_empty_adfiles') > elif t == "rpc.schannel_anon_setpw": > plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$%', description="anonymous password set") > plansmbtorture4testsuite(t, "nt4_dc_schannel", '//$SERVER_IP/tmp -U$%', description="anonymous password set (schannel enforced server-side)") >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 58a94dd143c..2eaf698c4e0 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -5412,3 +5412,194 @@ struct torture_suite *torture_vfs_fruit_timemachine(TALLOC_CTX *ctx) > > 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; >+} >diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c >index 64cb0e3d6c4..39cd573c9d6 100644 >--- a/source4/torture/vfs/vfs.c >+++ b/source4/torture/vfs/vfs.c >@@ -113,6 +113,7 @@ NTSTATUS torture_vfs_init(TALLOC_CTX *ctx) > 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_register_suite(ctx, suite); > >-- >2.17.2 > > >From c9584419a75f271933fe7d0c0a9d45d79bf1028c Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 3 Oct 2018 12:01:00 +0200 >Subject: [PATCH 06/43] vfs_fruit: add option > "wipe_intentionally_left_blank_rfork" > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 4b0e6e3d21f..89307a06f26 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -142,6 +142,7 @@ struct fruit_config_data { > const char *model; > bool time_machine; > off_t time_machine_max_size; >+ bool wipe_intentionally_left_blank_rfork; > > /* > * Additional options, all enabled by default, >@@ -2094,6 +2095,10 @@ static int init_fruit_config(vfs_handle_struct *handle) > config->time_machine_max_size = conv_str_size(tm_size_str); > } > >+ config->wipe_intentionally_left_blank_rfork = lp_parm_bool( >+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, >+ "wipe_intentionally_left_blank_rfork", false); >+ > SMB_VFS_HANDLE_SET_DATA(handle, config, > NULL, struct fruit_config_data, > return -1); >-- >2.17.2 > > >From 50cc7c0e0959135a783f98486f8da1d7889f2004 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Tue, 2 Oct 2018 16:05:28 +0200 >Subject: [PATCH 07/43] vfs_fruit: detect empty resource forks in ad_convert() > >For some reason the macOS client often writes AppleDouble files with a >non-zero sized resource fork, but the resource fork data is just >boilerplate data with the following string close to the start > > This resource fork intentionally left blank > >A dump with apple_dump looks like this: > >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 : 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 : .............. > >We can safely discard this Resource Fork data. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 1 - > source3/modules/vfs_fruit.c | 111 +++++++++++++++++++++++++- > 2 files changed, 110 insertions(+), 2 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index f2a27040a8e..8b9aed48b63 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,4 +1,3 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >-^samba3.vfs.fruit_conversion wipe_intentionally_left_blank_rfork.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\) > ^samba3.vfs.fruit_conversion delete_empty_adfiles.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\) >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 89307a06f26..a4795700299 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -468,6 +468,45 @@ static const uint32_t set_eid[] = { > AD_DEV, AD_INO, AD_SYN, AD_ID > }; > >+static char empty_resourcefork[] = { >+ 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 >+}; >+ > struct fio { > /* tcon config handle */ > struct fruit_config_data *config; >@@ -1282,6 +1321,70 @@ static bool ad_convert_truncate(struct adouble *ad, > return true; > } > >+static bool ad_convert_blank_rfork(struct adouble *ad, >+ bool *blank) >+{ >+ struct fruit_config_data *config = NULL; >+ uint8_t *map = MAP_FAILED; >+ size_t maplen; >+ int cmp; >+ ssize_t len; >+ int rc; >+ bool ok; >+ >+ *blank = false; >+ >+ SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config, >+ struct fruit_config_data, return false); >+ >+ if (!config->wipe_intentionally_left_blank_rfork) { >+ return true; >+ } >+ >+ if (ad_getentrylen(ad, ADEID_RFORK) != sizeof(empty_resourcefork)) { >+ return true; >+ } >+ >+ maplen = ad_getentryoff(ad, ADEID_RFORK) + >+ ad_getentrylen(ad, ADEID_RFORK); >+ >+ /* FIXME: direct use of mmap(), vfs_aio_fork does it too */ >+ map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED, >+ ad->ad_fd, 0); >+ if (map == MAP_FAILED) { >+ DBG_ERR("mmap AppleDouble: %s\n", strerror(errno)); >+ return false; >+ } >+ >+ cmp = memcmp(map + ADEDOFF_RFORK_DOT_UND, >+ empty_resourcefork, >+ sizeof(empty_resourcefork)); >+ rc = munmap(map, maplen); >+ if (rc != 0) { >+ DBG_ERR("munmap failed: %s\n", strerror(errno)); >+ return false; >+ } >+ >+ if (cmp != 0) { >+ return true; >+ } >+ >+ ad_setentrylen(ad, ADEID_RFORK, 0); >+ >+ ok = ad_pack(ad); >+ if (!ok) { >+ return false; >+ } >+ >+ len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0); >+ if (len != AD_DATASZ_DOT_UND) { >+ return false; >+ } >+ >+ *blank = true; >+ return true; >+} >+ > /** > * Convert from Apple's ._ file to Netatalk > * >@@ -1296,13 +1399,19 @@ static int ad_convert(struct adouble *ad, > { > bool ok; > bool converted_xattr = false; >+ bool blank; > > ok = ad_convert_xattr(ad, smb_fname, &converted_xattr); > if (!ok) { > return -1; > } > >- if (converted_xattr) { >+ ok = ad_convert_blank_rfork(ad, &blank); >+ if (!ok) { >+ return -1; >+ } >+ >+ if (converted_xattr || blank) { > ok = ad_convert_truncate(ad, smb_fname); > if (!ok) { > return -1; >-- >2.17.2 > > >From f4ccb47907c1f549a7d44007a5c8eaf77ebfa0cb Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 3 Oct 2018 12:01:00 +0200 >Subject: [PATCH 08/43] vfs_fruit: add option "delete_empty_adfiles" > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index a4795700299..6c00ce8048a 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -143,6 +143,7 @@ struct fruit_config_data { > bool time_machine; > off_t time_machine_max_size; > bool wipe_intentionally_left_blank_rfork; >+ bool delete_empty_adfiles; > > /* > * Additional options, all enabled by default, >@@ -2208,6 +2209,10 @@ static int init_fruit_config(vfs_handle_struct *handle) > SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, > "wipe_intentionally_left_blank_rfork", false); > >+ config->delete_empty_adfiles = lp_parm_bool( >+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, >+ "delete_empty_adfiles", false); >+ > SMB_VFS_HANDLE_SET_DATA(handle, config, > NULL, struct fruit_config_data, > return -1); >-- >2.17.2 > > >From b953a3b7239b61747851a9e0c0a49b2c3d0429e9 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Tue, 9 Oct 2018 14:54:31 +0200 >Subject: [PATCH 09/43] vfs_fruit: optionally delete AppleDouble files without > Resourcefork data > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13642 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 2 +- > source3/modules/vfs_fruit.c | 42 +++++++++++++++++++++++++++ > 2 files changed, 43 insertions(+), 1 deletion(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 8b9aed48b63..2b49e827d7e 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,3 +1,3 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >-^samba3.vfs.fruit_conversion delete_empty_adfiles.convert_xattr_and_empty_rfork_then_delete\(nt4_dc\) >+ >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 6c00ce8048a..5c986a7b3ea 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -1386,6 +1386,43 @@ static bool ad_convert_blank_rfork(struct adouble *ad, > return true; > } > >+static bool ad_convert_delete_adfile(struct adouble *ad, >+ const struct smb_filename *smb_fname) >+{ >+ struct fruit_config_data *config = NULL; >+ struct smb_filename *ad_name = NULL; >+ int rc; >+ >+ if (ad_getentrylen(ad, ADEID_RFORK) > 0) { >+ return true; >+ } >+ >+ SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config, >+ struct fruit_config_data, return false); >+ >+ if (!config->delete_empty_adfiles) { >+ return true; >+ } >+ >+ rc = adouble_path(talloc_tos(), smb_fname, &ad_name); >+ if (rc != 0) { >+ return false; >+ } >+ >+ rc = SMB_VFS_NEXT_UNLINK(ad->ad_handle, ad_name); >+ if (rc != 0) { >+ DBG_ERR("Unlinking [%s] failed: %s\n", >+ smb_fname_str_dbg(ad_name), strerror(errno)); >+ TALLOC_FREE(ad_name); >+ return false; >+ } >+ >+ DBG_WARNING("Unlinked [%s] after conversion\n", smb_fname_str_dbg(ad_name)); >+ TALLOC_FREE(ad_name); >+ >+ return true; >+} >+ > /** > * Convert from Apple's ._ file to Netatalk > * >@@ -1426,6 +1463,11 @@ static int ad_convert(struct adouble *ad, > return -1; > } > >+ ok = ad_convert_delete_adfile(ad, smb_fname); >+ if (!ok) { >+ return -1; >+ } >+ > return 0; > } > >-- >2.17.2 > > >From d23ded0fa5053aa539c60112d5c8ec45d4941cd4 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 23 Aug 2018 12:07:20 +0200 >Subject: [PATCH 10/43] vfs_streams_xattr: fix open implementation > >Since a long time the modules's open function happily returned success >when opening a non existent stream without O_CREAT. > >This change fixes it to return -1 and errno=ENOATTR if > >o get_ea_value() returns NT_STATUS_NOT_FOUND (eg mapped from > getxattr() = -1, errno=ENOATTR) and > >o flags doesn't contain O_CREAT > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_streams_xattr.c | 64 +++++++++++++++++------------ > 1 file changed, 38 insertions(+), 26 deletions(-) > >diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c >index 8714007cb8d..87c5589395a 100644 >--- a/source3/modules/vfs_streams_xattr.c >+++ b/source3/modules/vfs_streams_xattr.c >@@ -407,6 +407,7 @@ static int streams_xattr_open(vfs_handle_struct *handle, > char *xattr_name = NULL; > int pipe_fds[2]; > int fakefd = -1; >+ bool set_empty_xattr = false; > int ret; > > SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config, >@@ -440,39 +441,37 @@ static int streams_xattr_open(vfs_handle_struct *handle, > goto fail; > } > >- /* >- * Return a valid fd, but ensure any attempt to use it returns an error >- * (EPIPE). >- */ >- ret = pipe(pipe_fds); >- if (ret != 0) { >- goto fail; >- } >- >- close(pipe_fds[1]); >- pipe_fds[1] = -1; >- fakefd = pipe_fds[0]; >- > status = get_ea_value(talloc_tos(), handle->conn, NULL, > smb_fname, xattr_name, &ea); > > DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status))); > >- if (!NT_STATUS_IS_OK(status) >- && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { >- /* >- * The base file is not there. This is an error even if we got >- * O_CREAT, the higher levels should have created the base >- * file for us. >- */ >- DEBUG(10, ("streams_xattr_open: base file %s not around, " >- "returning ENOENT\n", smb_fname->base_name)); >- errno = ENOENT; >- goto fail; >+ if (!NT_STATUS_IS_OK(status)) { >+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { >+ /* >+ * The base file is not there. This is an error even if >+ * we got O_CREAT, the higher levels should have created >+ * the base file for us. >+ */ >+ DBG_DEBUG("streams_xattr_open: base file %s not around, " >+ "returning ENOENT\n", smb_fname->base_name); >+ errno = ENOENT; >+ goto fail; >+ } >+ >+ if (!(flags & O_CREAT)) { >+ errno = ENOATTR; >+ goto fail; >+ } >+ >+ set_empty_xattr = true; > } > >- if ((!NT_STATUS_IS_OK(status) && (flags & O_CREAT)) || >- (flags & O_TRUNC)) { >+ if (flags & O_TRUNC) { >+ set_empty_xattr = true; >+ } >+ >+ if (set_empty_xattr) { > /* > * The attribute does not exist or needs to be truncated > */ >@@ -495,6 +494,19 @@ static int streams_xattr_open(vfs_handle_struct *handle, > } > } > >+ /* >+ * Return a valid fd, but ensure any attempt to use it returns an error >+ * (EPIPE). >+ */ >+ ret = pipe(pipe_fds); >+ if (ret != 0) { >+ goto fail; >+ } >+ >+ close(pipe_fds[1]); >+ pipe_fds[1] = -1; >+ fakefd = pipe_fds[0]; >+ > sio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct stream_io, NULL); > if (sio == NULL) { > errno = ENOMEM; >-- >2.17.2 > > >From fc0235f50fd26b8704d41aaa5665dd588123c4e9 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 17 Oct 2018 10:54:10 +0200 >Subject: [PATCH 11/43] vfs_streams_xattr: consistently log dev/ino as hex > >open_file_ntcreate() logs dev/ino in hex format if it hits a "dev/ino >mismatch". Logging it consistently as hex helps debugging such mismatch >issues. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_streams_xattr.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > >diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c >index 87c5589395a..6fbf568ba18 100644 >--- a/source3/modules/vfs_streams_xattr.c >+++ b/source3/modules/vfs_streams_xattr.c >@@ -52,9 +52,9 @@ static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname) > SMB_INO_T result; > char *upper_sname; > >- DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n", >- (unsigned long)sbuf->st_ex_dev, >- (unsigned long)sbuf->st_ex_ino, sname)); >+ DBG_DEBUG("stream_inode called for 0x%jx/0x%jx [%s]\n", >+ (uintmax_t)sbuf->st_ex_dev, >+ (uintmax_t)sbuf->st_ex_ino, sname); > > upper_sname = talloc_strdup_upper(talloc_tos(), sname); > SMB_ASSERT(upper_sname != NULL); >@@ -73,7 +73,7 @@ static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname) > /* Hopefully all the variation is in the lower 4 (or 8) bytes! */ > memcpy(&result, hash, sizeof(result)); > >- DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result)); >+ DBG_DEBUG("stream_inode returns 0x%jx\n", (uintmax_t)result); > > return result; > } >-- >2.17.2 > > >From a5a16d8d2596d881eb9e8ab615bb7ae954e509ef Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Fri, 19 Oct 2018 22:21:10 +0200 >Subject: [PATCH 12/43] s4:torture/vfs/fruit: skip a few tests when running > against a macOS SMB server > >These tests are designed to test specific vfs_fruit functionality. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 2eaf698c4e0..b15958afe07 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -2111,6 +2111,11 @@ static bool test_adouble_conversion(struct torture_context *tctx, > ":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); > >@@ -2185,6 +2190,11 @@ static bool test_adouble_conversion_wo_xattr(struct torture_context *tctx, > union smb_search_data *d; > const char *data = "This resource fork intentionally left blank"; > size_t datalen = strlen(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); > >@@ -4742,6 +4752,11 @@ static bool test_nfs_aces(struct torture_context *tctx, > 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"); >-- >2.17.2 > > >From 4f1ab9e6deff67fe7afcd5d3fa1b65c20af5caf8 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 17 Oct 2018 10:51:45 +0200 >Subject: [PATCH 13/43] s4:torture/vfs/fruit: fix a few error checks in "delete > AFP_AfpInfo by writing all 0" > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index b15958afe07..3039c4ecc5b 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3675,8 +3675,8 @@ static bool test_afpinfo_all0(struct torture_context *tctx, > create.in.fname = fname; > > status = smb2_create(tree, mem_ctx, &create); >- torture_assert_goto(tctx, ret == true, ret, done, >- "smb2_create failed\n"); >+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, >+ "smb2_create failed\n"); > baseh = create.out.file.handle; > > ZERO_STRUCT(create); >@@ -3686,8 +3686,8 @@ static bool test_afpinfo_all0(struct torture_context *tctx, > create.in.fname = sname; > > status = smb2_create(tree, mem_ctx, &create); >- torture_assert_goto(tctx, ret == true, ret, done, >- "smb2_create failed\n"); >+ 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); >-- >2.17.2 > > >From 0206cb029e393de74adb4d3db143583017402cd3 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 11 Oct 2018 17:13:52 +0200 >Subject: [PATCH 14/43] s4:torture/vfs/fruit: set share_access to > NTCREATEX_SHARE_ACCESS_MASK in check_stream_list > >Avoid sharing conflicts with other opens on the basefile. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 3039c4ecc5b..d067a9c97e2 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3053,6 +3053,7 @@ static bool check_stream_list(struct smb2_tree *tree, > 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; >-- >2.17.2 > > >From ff782eafc6df73259bc47716853e18af67c5f361 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 15:31:21 +0200 >Subject: [PATCH 15/43] s4:torture/vfs/fruit: update test "SMB2/CREATE context > AAPL" to work against macOS > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index d067a9c97e2..0e463a7e451 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -2306,6 +2306,7 @@ static bool test_aapl(struct torture_context *tctx, > 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; >@@ -2424,8 +2425,11 @@ static bool test_aapl(struct torture_context *tctx, > goto done; > } > >+ if (is_osx_server) { >+ expected_vol_caps = 5; >+ } > aapl_vol_caps = BVAL(aapl->data.data, 24); >- if (aapl_vol_caps != 0) { >+ 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", >-- >2.17.2 > > >From b79798c9bad486baca70d074c71f8492897ab674 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 15:39:12 +0200 >Subject: [PATCH 16/43] s4:torture/vfs/fruit: update test "stream names" to > work with macOS > >o create the basefile before trying to create a stream on it, otherwise > this fails on macOS > >o write something to the stream, otherwise the stream is not listed as > macOS hides 0-byte sized streams > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 0e463a7e451..681dde53d06 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3132,6 +3132,9 @@ static bool test_stream_names(struct torture_context *tctx, > 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; >@@ -3146,6 +3149,11 @@ static bool test_stream_names(struct torture_context *tctx, > > 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); >-- >2.17.2 > > >From 27575e607e1b07b90f2062db99d0b3327c4d23b9 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 16:03:03 +0200 >Subject: [PATCH 17/43] s4:torture/vfs/fruit: update test "rename_dir_openfile" > to work against macOS > >The test opens a directory twice where the first open didn't allow >sharing. No idea why this works against Samba, against macOS the second >open got a sharing violation. Obvious fix: add proper sharing. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 681dde53d06..0b5f7726c9d 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3190,7 +3190,7 @@ static bool test_rename_dir_openfile(struct torture_context *torture, > 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.share_access = NTCREATEX_SHARE_ACCESS_MASK; > io.smb2.in.alloc_size = 0; > io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; > io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; >@@ -3252,7 +3252,7 @@ static bool test_rename_dir_openfile(struct torture_context *torture, > 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.share_access = NTCREATEX_SHARE_ACCESS_MASK; > io.smb2.in.alloc_size = 0; > io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; > io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; >-- >2.17.2 > > >From d63926e14e998b6b90480d9045dc4b3a6359598a Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 16:24:19 +0200 >Subject: [PATCH 18/43] s4:torture/vfs/fruit: update test "read open rsrc after > rename" to work with macOS > >macOS SMB server seems to return NT_STATUS_SHARING_VIOLATION in this >case while Windows 2016 returns NT_STATUS_ACCESS_DENIED. > >Lets stick with the Windows error code for now in the Samba fileserver, >but let the test pass against macOS. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 17 +++++++++++++++-- > 1 file changed, 15 insertions(+), 2 deletions(-) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 0b5f7726c9d..13c8cc9288c 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -4182,6 +4182,8 @@ static bool test_rename_and_read_rsrc(struct torture_context *tctx, > 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"); >@@ -4232,14 +4234,25 @@ static bool test_rename_and_read_rsrc(struct torture_context *tctx, > 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, NT_STATUS_ACCESS_DENIED, ret, done, >+ tctx, status, expected_status, ret, done, > "smb2_setinfo_file failed"); > >- smb2_util_close(tree, h1); > 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); >-- >2.17.2 > > >From cac085de923b04f3fe64e215e143b4b160f99536 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Tue, 9 Oct 2018 18:48:08 +0200 >Subject: [PATCH 19/43] s4:torture/vfs/fruit: expand existing test "setinfo > delete-on-close AFP_AfpInfo" a little bit > >Add a check that verifies a create on a stream gets >NT_STATUS_DELETE_PENDING after delete-on-close has been set. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 13c8cc9288c..85643038764 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3453,6 +3453,10 @@ static bool test_setinfo_delete_on_close(struct torture_context *tctx, > 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" > }; >@@ -3494,6 +3498,19 @@ static bool test_setinfo_delete_on_close(struct torture_context *tctx, > 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); >-- >2.17.2 > > >From 624bfed60b29112d3b8c5d798e96b4b7a8900fdf Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 10 Oct 2018 12:47:07 +0200 >Subject: [PATCH 20/43] s4:torture/vfs/fruit: expand existing vfs_test "null > afpinfo" > >This adds a check that a read on a seperate handle also sees the >previously created AFP_AfpInfo stream. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 85643038764..3b0c3cdae85 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -4094,6 +4094,8 @@ static bool test_null_afpinfo(struct torture_context *tctx, > 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"); > >@@ -4132,6 +4134,20 @@ static bool test_null_afpinfo(struct torture_context *tctx, > 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"); > >-- >2.17.2 > > >From 676842e2d68243ecc88935db610247e71a1cfc4e Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 15:17:08 +0200 >Subject: [PATCH 21/43] s4:torture/vfs/fruit: update test "creating rsrc with > read-only access" for newer macOS versions > >While this operation failed against older macOS versions, it passes >against versions 10.12 and newer. Update the test accordingly, a >subsequent commit will then update our implementation. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 4 +++- > source4/torture/vfs/fruit.c | 28 +-------------------------- > 2 files changed, 4 insertions(+), 28 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 2b49e827d7e..a2758ffeded 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,3 +1,5 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >- >+^samba3.vfs.fruit metadata_netatalk.creating rsrc with read-only access\(nt4_dc\) >+^samba3.vfs.fruit metadata_stream.creating rsrc with read-only access\(nt4_dc\) >+^samba3.vfs.fruit streams_depot.creating rsrc with read-only access\(nt4_dc\) >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 3b0c3cdae85..f4de09576a7 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -2045,35 +2045,9 @@ static bool test_rfork_create_ro(struct torture_context *tctx, > } > > torture_comment(tctx, "(%s) Try opening read-only with " >- "open_if create disposition, should return ENOENT\n", >+ "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_equal_goto(tctx, status, >- NT_STATUS_OBJECT_NAME_NOT_FOUND, >- ret, done, "smb2_create failed\n"); >- >- torture_comment(tctx, "(%s) Now write something to the " >- "rsrc stream, then the same open should succeed\n", >- __location__); >- >- 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\n"); >- >- 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"); >- > ZERO_STRUCT(create); > create.in.fname = rfork; > create.in.create_disposition = NTCREATEX_DISP_OPEN_IF; >-- >2.17.2 > > >From 02b0916e0cc296fc1fcad1a7eb95365bd7cdfd83 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 22 Oct 2018 12:32:09 +0200 >Subject: [PATCH 22/43] vfs_fruit: update handling of read-only creation of > resource fork > >macOS SMB server versions supports this since 10.12, so we adapt our >behaviour. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 3 --- > source3/modules/vfs_fruit.c | 23 +++-------------------- > 2 files changed, 3 insertions(+), 23 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index a2758ffeded..6307e2b3404 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,5 +1,2 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >-^samba3.vfs.fruit metadata_netatalk.creating rsrc with read-only access\(nt4_dc\) >-^samba3.vfs.fruit metadata_stream.creating rsrc with read-only access\(nt4_dc\) >-^samba3.vfs.fruit streams_depot.creating rsrc with read-only access\(nt4_dc\) >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 5c986a7b3ea..b51eda1146b 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -3575,12 +3575,9 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, > goto exit; > } > >- /* Sanitize flags */ >- if (flags & O_WRONLY) { >- /* We always need read access for the metadata header too */ >- flags &= ~O_WRONLY; >- flags |= O_RDWR; >- } >+ /* We always need read/write access for the metadata header too */ >+ flags &= ~(O_RDONLY | O_WRONLY); >+ flags |= O_RDWR; > > hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, > flags, mode); >@@ -3667,20 +3664,6 @@ static int fruit_open_rsrc(vfs_handle_struct *handle, > SMB_VFS_HANDLE_GET_DATA(handle, config, > struct fruit_config_data, return -1); > >- if (((flags & O_ACCMODE) == O_RDONLY) >- && (flags & O_CREAT) >- && !VALID_STAT(fsp->fsp_name->st)) >- { >- /* >- * This means the stream doesn't exist. macOS SMB server fails >- * this with NT_STATUS_OBJECT_NAME_NOT_FOUND, so must we. Cf bug >- * 12565 and the test for this combination in >- * test_rfork_create(). >- */ >- errno = ENOENT; >- return -1; >- } >- > switch (config->rsrc) { > case FRUIT_RSRC_STREAM: > fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); >-- >2.17.2 > > >From 1e97f46a8cdbdeb51e66383791b97292cf07df09 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 22 Oct 2018 12:43:16 +0200 >Subject: [PATCH 23/43] s4:torture/vfs/fruit: expand test "setinfo eof stream" > >o Adds checks verifying that after setting eof to 0 on a stream, a > subsequent open gets ENOENT, before and after closing the handle that > had been used to set eof to 0. > >o Verify that a write to a handle succeeds after that handle has been > used to set eof to 0 on a stream. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 3 ++ > source4/torture/vfs/fruit.c | 61 +++++++++++++++++++++++++++ > 2 files changed, 64 insertions(+) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 6307e2b3404..5ecba522d4a 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,2 +1,5 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >+^samba3.vfs.fruit metadata_netatalk.setinfo eof stream\(nt4_dc\) >+^samba3.vfs.fruit metadata_stream.setinfo eof stream\(nt4_dc\) >+^samba3.vfs.fruit streams_depot.setinfo eof stream\(nt4_dc\) >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index f4de09576a7..ee2c5e3fb75 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -4984,8 +4984,32 @@ static bool test_setinfo_stream_eof(struct torture_context *tctx, > 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, >@@ -5064,6 +5088,18 @@ static bool test_setinfo_stream_eof(struct torture_context *tctx, > 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); >@@ -5123,6 +5159,31 @@ static bool test_setinfo_stream_eof(struct torture_context *tctx, > 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); >-- >2.17.2 > > >From f812760e576399ca598d58a44c124c3ba5bf08e5 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 14:52:23 +0200 >Subject: [PATCH 24/43] s4:torture/vfs/fruit: write some data to a just created > teststream > >Doesn't currently make a difference, but this prepares for a later >change in vfs_fruit that will filter out empty streams (which is the >macOS behaviour). > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index ee2c5e3fb75..c77cc981b84 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -5285,6 +5285,11 @@ static bool test_stream_names_local(struct torture_context *tctx, > > 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", >-- >2.17.2 > > >From 79599c70cf4643ddb51c5b9179c68148b3e978a6 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 14:54:48 +0200 >Subject: [PATCH 25/43] vfs_fruit: don't unlink 0-byte size truncated streams > >This caused all sort of havoc with subsequent SMB request that acted on >the handle of the then deleted backend storage (file or blob, depending >on the used streams module). > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 7 ------- > 1 file changed, 7 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index b51eda1146b..1446461a8a3 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5816,13 +5816,6 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle, > (intmax_t)offset); > > if (fio == NULL) { >- if (offset == 0 && >- global_fruit_config.nego_aapl && >- is_ntfs_stream_smb_fname(fsp->fsp_name) && >- !is_ntfs_default_stream_smb_fname(fsp->fsp_name)) >- { >- return SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name); >- } > return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); > } > >-- >2.17.2 > > >From f2fe4968808de7d631a605fdeeb7037d11e050c9 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 22 Oct 2018 14:01:34 +0200 >Subject: [PATCH 26/43] s4:torture/vfs/fruit: enable AAPL extensions in a bunch > of tests > >These tests check for macOS SMB server specific behaviour. They work >currently against Samba without enabling AAPL because in vfs_fruit we're >currently don't check whether AAPL has been negotiated in one place. A >subsequent commit will change that and this commit prepares for that >change. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index c77cc981b84..589c25cfda2 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -1810,6 +1810,9 @@ static bool test_rfork_truncate(struct torture_context *tctx, > 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); >@@ -1928,6 +1931,9 @@ static bool test_rfork_create(struct torture_context *tctx, > }; > 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); >@@ -3938,6 +3944,9 @@ static bool test_setinfo_eof_resource(struct torture_context *tctx, > > 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); >@@ -4904,6 +4913,9 @@ static bool test_setinfo_stream_eof(struct torture_context *tctx, > 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); >-- >2.17.2 > > >From 3c76b503a2b03b5408f71987a56ecd82f05b3960 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 15:28:06 +0200 >Subject: [PATCH 27/43] vfs_fruit: use check on global_fruit_config.nego_aapl > for macOS specific behaviour > >Ensure any non MS compliant protocol behaviour targetted at supporting >macOS clients are only effective if the client negotiated AAPL. > >Currently this only guards the resource fork which only macOS client are >going to use, but subsequent commits add more this at this place. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 1446461a8a3..62e741c4ae2 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5892,7 +5892,8 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle, > * > * Cf the vfs_fruit torture tests in test_rfork_create(). > */ >- if (is_afpresource_stream(fsp->fsp_name) && >+ if (global_fruit_config.nego_aapl && >+ is_afpresource_stream(fsp->fsp_name) && > create_disposition == FILE_OPEN) > { > if (fsp->fsp_name->st.st_ex_size == 0) { >-- >2.17.2 > > >From dfaf4a6c2ca45c91b8311274ccf03afdb7b26d6c Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 14:53:50 +0200 >Subject: [PATCH 28/43] vfs_fruit: filter empty streams > >First step in achieving macOS compliant behaviour wrt to empty streams: >- hide empty streams in streaminfo >- prevent opens of empty streams > >This means that we may carry 0-byte sized streams in our streams >backend, but this shouldn't really hurt. > >The previous attempt of deleting the streams when an SMB setinfo eof to >0 request came in, turned out be a road into desaster. > >We could set delete-on-close on the stream, but that means we'd have to >check for it for every write on a stream and checking the >delete-on-close bits requires fetching the locking.tdb record, so this >is expensive and I'd like to avoid that overhead. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 3 -- > source3/modules/vfs_fruit.c | 44 +++++++++++++++++++++++---- > 2 files changed, 38 insertions(+), 9 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 5ecba522d4a..6307e2b3404 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,5 +1,2 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >-^samba3.vfs.fruit metadata_netatalk.setinfo eof stream\(nt4_dc\) >-^samba3.vfs.fruit metadata_stream.setinfo eof stream\(nt4_dc\) >-^samba3.vfs.fruit streams_depot.setinfo eof stream\(nt4_dc\) >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 62e741c4ae2..181038c9817 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5598,6 +5598,36 @@ static NTSTATUS fruit_streaminfo_rsrc(vfs_handle_struct *handle, > return status; > } > >+static void fruit_filter_empty_streams(unsigned int *pnum_streams, >+ struct stream_struct **pstreams) >+{ >+ unsigned num_streams = *pnum_streams; >+ struct stream_struct *streams = *pstreams; >+ unsigned i = 0; >+ >+ if (!global_fruit_config.nego_aapl) { >+ return; >+ } >+ >+ while (i < num_streams) { >+ struct smb_filename smb_fname = (struct smb_filename) { >+ .stream_name = streams[i].name, >+ }; >+ >+ if (is_ntfs_default_stream_smb_fname(&smb_fname) >+ || streams[i].size > 0) >+ { >+ i++; >+ continue; >+ } >+ >+ streams[i] = streams[num_streams - 1]; >+ num_streams--; >+ } >+ >+ *pnum_streams = num_streams; >+} >+ > static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, > struct files_struct *fsp, > const struct smb_filename *smb_fname, >@@ -5619,6 +5649,8 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, > return status; > } > >+ fruit_filter_empty_streams(pnum_streams, pstreams); >+ > status = fruit_streaminfo_meta(handle, fsp, smb_fname, > mem_ctx, pnum_streams, pstreams); > if (!NT_STATUS_IS_OK(status)) { >@@ -5893,13 +5925,13 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle, > * Cf the vfs_fruit torture tests in test_rfork_create(). > */ > if (global_fruit_config.nego_aapl && >- is_afpresource_stream(fsp->fsp_name) && >- create_disposition == FILE_OPEN) >+ create_disposition == FILE_OPEN && >+ smb_fname->st.st_ex_size == 0 && >+ is_ntfs_stream_smb_fname(smb_fname) && >+ !(is_ntfs_default_stream_smb_fname(smb_fname))) > { >- if (fsp->fsp_name->st.st_ex_size == 0) { >- status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >- goto fail; >- } >+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ goto fail; > } > > if (is_ntfs_stream_smb_fname(smb_fname) >-- >2.17.2 > > >From 8a12a00823d672eb77c42b76c226d9da0b01f2c6 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 10 Oct 2018 18:45:56 +0200 >Subject: [PATCH 29/43] s4:torture/util: add torture_smb2_open() > >This seems to be missing: a simple wrapper to just open a file without >fancy options. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/smb2/util.c | 30 ++++++++++++++++++++++++++++++ > 1 file changed, 30 insertions(+) > >diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c >index 65090b0e8b7..ac8a0d5df77 100644 >--- a/source4/torture/smb2/util.c >+++ b/source4/torture/smb2/util.c >@@ -527,6 +527,36 @@ NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, > SEC_RIGHTS_FILE_ALL); > } > >+/* >+ create and return a handle to a test file >+ with a specific access mask >+*/ >+NTSTATUS torture_smb2_open(struct smb2_tree *tree, >+ const char *fname, >+ uint32_t desired_access, >+ struct smb2_handle *handle) >+{ >+ struct smb2_create io; >+ NTSTATUS status; >+ >+ io = (struct smb2_create) { >+ .in.fname = fname, >+ .in.desired_access = desired_access, >+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, >+ .in.create_disposition = NTCREATEX_DISP_OPEN, >+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, >+ }; >+ >+ status = smb2_create(tree, tree, &io); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ *handle = io.out.file.handle; >+ >+ return NT_STATUS_OK; >+} >+ > /* > create and return a handle to a test directory > with specific desired access >-- >2.17.2 > > >From 8948096d058d7c4bc019a9b0faed44f6f1651837 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Thu, 11 Oct 2018 17:14:50 +0200 >Subject: [PATCH 30/43] s4:torture/vfs/fruit: add check_stream_list_handle() > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source4/torture/vfs/fruit.c | 62 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 62 insertions(+) > >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 589c25cfda2..20e5e3f3495 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3082,6 +3082,68 @@ static bool check_stream_list(struct smb2_tree *tree, > return ret; > } > >+#if 0 >+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; >+} >+#endif >+ > /* > test stream names > */ >-- >2.17.2 > > >From 325fb2e25bfbe2c12658f011737e4a03eafb83e6 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 22 Oct 2018 16:21:21 +0200 >Subject: [PATCH 31/43] s4:torture/vfs/fruit: add test "empty_stream" > >One to rule them all: consistently test critical operations on all >streams relevant to macOS clients: the FinderInfo stream, the Resource >Fork stream and an arbitrary stream that macOS maps to xattrs when >written to on a macOS SMB server. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 3 + > source4/torture/vfs/fruit.c | 613 +++++++++++++++++++++++++- > 2 files changed, 614 insertions(+), 2 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 6307e2b3404..2d3c21caf91 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,2 +1,5 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >+^samba3.vfs.fruit metadata_netatalk.empty_stream\(nt4_dc\) >+^samba3.vfs.fruit metadata_stream.empty_stream\(nt4_dc\) >+^samba3.vfs.fruit streams_depot.empty_stream\(nt4_dc\) >diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c >index 20e5e3f3495..a88576b7e25 100644 >--- a/source4/torture/vfs/fruit.c >+++ b/source4/torture/vfs/fruit.c >@@ -3082,7 +3082,6 @@ static bool check_stream_list(struct smb2_tree *tree, > return ret; > } > >-#if 0 > static bool check_stream_list_handle(struct smb2_tree *tree, > struct torture_context *tctx, > struct smb2_handle h, >@@ -3142,7 +3141,6 @@ static bool check_stream_list_handle(struct smb2_tree *tree, > TALLOC_FREE(tmp_ctx); > return ret; > } >-#endif > > /* > test stream names >@@ -5264,6 +5262,616 @@ static bool test_setinfo_stream_eof(struct torture_context *tctx, > 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; >+ 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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.streams_closed_handle = {"::$DATA"}, >+ .write.size = 60, >+ .write.initial_status = NT_STATUS_OK, >+ .write.final_status = NT_STATUS_OK, >+ .write.num_streams_open_handle = 2, >+ .write.num_streams_closed_handle = 2, >+ .write.streams_open_handle = {"::$DATA", AFPINFO_STREAM}, >+ .write.streams_closed_handle = {"::$DATA", AFPINFO_STREAM}, >+ .overwrite.size = 60, >+ .overwrite.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.num_streams_open_handle = 1, >+ .overwrite.num_streams_closed_handle = 1, >+ .overwrite.streams_open_handle = {"::$DATA"}, >+ .overwrite.streams_closed_handle = {"::$DATA"}, >+ .eof.size = 60, >+ .eof.initial_status = NT_STATUS_OK, >+ .eof.final_status = NT_STATUS_OK, >+ .eof.num_streams_open_handle = 2, >+ .eof.num_streams_closed_handle = 2, >+ .eof.streams_open_handle = {"::$DATA", AFPINFO_STREAM}, >+ .eof.streams_closed_handle = {"::$DATA", AFPINFO_STREAM}, >+ .doc.size = 60, >+ .doc.initial_status = NT_STATUS_DELETE_PENDING, >+ .doc.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .doc.num_streams_open_handle = 2, >+ .doc.num_streams_closed_handle = 1, >+ .doc.streams_open_handle = {"::$DATA", AFPINFO_STREAM}, >+ .doc.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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.streams_closed_handle = {"::$DATA"}, >+ .write.size = 3, >+ .write.initial_status = NT_STATUS_OK, >+ .write.final_status = NT_STATUS_OK, >+ .write.num_streams_open_handle = 2, >+ .write.num_streams_closed_handle = 2, >+ .write.streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM}, >+ .write.streams_closed_handle = {"::$DATA", AFPRESOURCE_STREAM}, >+ .overwrite.size = 0, >+ .overwrite.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.num_streams_open_handle = 1, >+ .overwrite.num_streams_closed_handle = 1, >+ .overwrite.streams_open_handle = {"::$DATA"}, >+ .overwrite.streams_closed_handle = {"::$DATA"}, >+ .eof.size = 0, >+ .eof.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .eof.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .eof.num_streams_open_handle = 1, >+ .eof.num_streams_closed_handle = 1, >+ .eof.streams_open_handle = {"::$DATA"}, >+ .eof.streams_closed_handle = {"::$DATA"}, >+ .doc.size = 3, >+ .doc.initial_status = NT_STATUS_DELETE_PENDING, >+ .doc.final_status = NT_STATUS_OK, >+ .doc.num_streams_open_handle = 2, >+ .doc.num_streams_closed_handle = 2, >+ .doc.streams_open_handle = {"::$DATA", AFPRESOURCE_STREAM}, >+ .doc.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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.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, >+ .create.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .create.num_streams_open_handle = 1, >+ .create.num_streams_closed_handle = 1, >+ .create.streams_open_handle = {"::$DATA"}, >+ .create.streams_closed_handle = {"::$DATA"}, >+ .write.size = 3, >+ .write.initial_status = NT_STATUS_OK, >+ .write.final_status = NT_STATUS_OK, >+ .write.num_streams_open_handle = 2, >+ .write.num_streams_closed_handle = 2, >+ .write.streams_open_handle = {"::$DATA", ":foo:$DATA"}, >+ .write.streams_closed_handle = {"::$DATA", ":foo:$DATA"}, >+ .overwrite.size = 0, >+ .overwrite.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .overwrite.num_streams_open_handle = 1, >+ .overwrite.num_streams_closed_handle = 1, >+ .overwrite.streams_open_handle = {"::$DATA"}, >+ .overwrite.streams_closed_handle = {"::$DATA"}, >+ .eof.size = 0, >+ .eof.initial_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .eof.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .eof.num_streams_open_handle = 1, >+ .eof.num_streams_closed_handle = 1, >+ .eof.streams_open_handle = {"::$DATA"}, >+ .eof.streams_closed_handle = {"::$DATA"}, >+ .doc.size = 3, >+ .doc.initial_status = NT_STATUS_DELETE_PENDING, >+ .doc.final_status = NT_STATUS_OBJECT_NAME_NOT_FOUND, >+ .doc.num_streams_open_handle = 2, >+ .doc.num_streams_closed_handle = 1, >+ .doc.streams_open_handle = {"::$DATA", ":foo:$DATA"}, >+ .doc.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, >+ {NULL} >+ }; >+ >+ 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; >+} >+ > /* > * 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 >@@ -5307,6 +5915,7 @@ struct torture_suite *torture_vfs_fruit(TALLOC_CTX *ctx) > 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); > > return suite; > } >-- >2.17.2 > > >From 740117e8cc7751debf5408667592481d26be61dd Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 17 Oct 2018 19:07:11 +0200 >Subject: [PATCH 32/43] vfs_fruit: update and add some debugging of dev/ino > >Aids in debugging dev/ino mismatch failures in open_file_ntcreate. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 181038c9817..7af7c43755e 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -2374,6 +2374,10 @@ static SMB_INO_T fruit_inode(const SMB_STRUCT_STAT *sbuf, const char *sname) > SMB_INO_T result; > char *upper_sname; > >+ DBG_DEBUG("fruit_inode called for 0x%jx/0x%jx [%s]\n", >+ (uintmax_t)sbuf->st_ex_dev, >+ (uintmax_t)sbuf->st_ex_ino, sname); >+ > upper_sname = talloc_strdup_upper(talloc_tos(), sname); > SMB_ASSERT(upper_sname != NULL); > >@@ -2391,8 +2395,8 @@ static SMB_INO_T fruit_inode(const SMB_STRUCT_STAT *sbuf, const char *sname) > /* Hopefully all the variation is in the lower 4 (or 8) bytes! */ > memcpy(&result, hash, sizeof(result)); > >- DEBUG(10, ("fruit_inode \"%s\": ino=0x%llu\n", >- sname, (unsigned long long)result)); >+ DBG_DEBUG("fruit_inode \"%s\": ino=0x%jx\n", >+ sname, (uintmax_t)result); > > return result; > } >@@ -4815,6 +4819,11 @@ static int fruit_stat_base(vfs_handle_struct *handle, > rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname); > } > smb_fname->stream_name = tmp_stream_name; >+ >+ DBG_DEBUG("fruit_stat_base [%s] dev [0x%jx] ino [0x%jx]\n", >+ smb_fname->base_name, >+ (uintmax_t)smb_fname->st.st_ex_dev, >+ (uintmax_t)smb_fname->st.st_ex_ino); > return rc; > } > >-- >2.17.2 > > >From cd88ba0bdf413751d394261b21367ca4da2be344 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 15 Oct 2018 18:38:33 +0200 >Subject: [PATCH 33/43] vfs_fruit: remove resource fork special casing > >Directly unlinking a file with open handles is not good, don't do it. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 8 -------- > 1 file changed, 8 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 7af7c43755e..9a943452642 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5736,10 +5736,6 @@ static int fruit_ftruncate_rsrc_xattr(struct vfs_handle_struct *handle, > struct files_struct *fsp, > off_t offset) > { >- if (offset == 0) { >- return SMB_VFS_FREMOVEXATTR(fsp, AFPRESOURCE_EA_NETATALK); >- } >- > #ifdef HAVE_ATTROPEN > return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); > #endif >@@ -5787,10 +5783,6 @@ static int fruit_ftruncate_rsrc_stream(struct vfs_handle_struct *handle, > struct files_struct *fsp, > off_t offset) > { >- if (offset == 0) { >- return SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name); >- } >- > return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); > } > >-- >2.17.2 > > >From 5de35fbb1dd47526a545f19a009ddc1888fd1584 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Mon, 22 Oct 2018 16:56:46 +0200 >Subject: [PATCH 34/43] vfs_fruit: add fio->created > >fio->created tracks whether a create created a stream. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 9a943452642..c3ad91b3986 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -514,6 +514,9 @@ struct fio { > > /* Denote stream type, meta or rsrc */ > adouble_type_t type; >+ >+ /* Whether the create created the stream */ >+ bool created; > }; > > /* >@@ -5885,6 +5888,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle, > NTSTATUS status; > struct fruit_config_data *config = NULL; > files_struct *fsp = NULL; >+ struct fio *fio = NULL; > > status = check_aapl(handle, req, in_context_blobs, out_context_blobs); > if (!NT_STATUS_IS_OK(status)) { >@@ -5935,6 +5939,11 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle, > goto fail; > } > >+ fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); >+ if (fio != NULL && pinfo != NULL && *pinfo == FILE_WAS_CREATED) { >+ fio->created = true; >+ } >+ > if (is_ntfs_stream_smb_fname(smb_fname) > || fsp->is_directory) { > return status; >-- >2.17.2 > > >From 100f52c4c9c74d770390edbd17e439a67053afde Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Aug 2018 15:22:57 +0200 >Subject: [PATCH 35/43] vfs_fruit: prepare struct fio for fake-fd and on-demand > opening > >Not used for now, that comes in the subsequent commits. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index c3ad91b3986..326976947a6 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -517,6 +517,17 @@ struct fio { > > /* Whether the create created the stream */ > bool created; >+ >+ /* >+ * AFP_AfpInfo stream created, but not written yet, thus still a fake >+ * pipe fd. This is set to true in fruit_open_meta if there was no >+ * exisiting stream but the caller requested O_CREAT. It is later set to >+ * false when we get a write on the stream that then does open and >+ * create the stream. >+ */ >+ bool fake_fd; >+ int flags; >+ int mode; > }; > > /* >-- >2.17.2 > > >From 25fa0b39d1210d267d915f36c55adacf47149cfb Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Aug 2018 15:21:08 +0200 >Subject: [PATCH 36/43] vfs_fruit: prepare fruit_pwrite_meta() for on-demand > opening and writing > >This avoid creating files or blobs in our streams backend when a client >creates a stream but hasn't written anything yet. This is the only sane >way to implement the following semantics: > >* client 1: create stream "file:foo" > >* client 2: open stream "file:foo" > >The second operation of client 2 must fail with NT_STATUS_NOT_FOUND. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 34 ++++++++++++++++++++++++++++++++++ > 1 file changed, 34 insertions(+) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 326976947a6..e6d6a9df087 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -4495,10 +4495,44 @@ static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle, > files_struct *fsp, const void *data, > size_t n, off_t offset) > { >+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); > AfpInfo *ai = NULL; > size_t nwritten; >+ int ret; > bool ok; > >+ DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n", >+ fsp_str_dbg(fsp), (intmax_t)offset, n); >+ >+ if (fio == NULL) { >+ return -1; >+ } >+ >+ if (fio->fake_fd) { >+ int fd; >+ >+ ret = SMB_VFS_NEXT_CLOSE(handle, fsp); >+ if (ret != 0) { >+ DBG_ERR("Close [%s] failed: %s\n", >+ fsp_str_dbg(fsp), strerror(errno)); >+ fsp->fh->fd = -1; >+ return -1; >+ } >+ >+ fd = SMB_VFS_NEXT_OPEN(handle, >+ fsp->fsp_name, >+ fsp, >+ fio->flags, >+ fio->mode); >+ if (fd == -1) { >+ DBG_ERR("On-demand create [%s] in write failed: %s\n", >+ fsp_str_dbg(fsp), strerror(errno)); >+ return -1; >+ } >+ fsp->fh->fd = fd; >+ fio->fake_fd = false; >+ } >+ > ai = afpinfo_unpack(talloc_tos(), data); > if (ai == NULL) { > return -1; >-- >2.17.2 > > >From c921016a40379f8b473a74330db9b2a12a49e3dd Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Aug 2018 15:22:08 +0200 >Subject: [PATCH 37/43] vfs_fruit: prepare fruit_pread_meta() for reading on > fake-fd > >If the read on the stream fails we may have hit a handle on a just >created stream (fio->created=true) with no data written yet. > >If that's the case return an empty initialized FinderInfo blob. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index e6d6a9df087..5dbdeedab89 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -4194,8 +4194,7 @@ static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle, > int ret; > > nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); >- >- if (nread == n) { >+ if (nread == -1 || nread == n) { > return nread; > } > >@@ -4299,6 +4298,25 @@ static ssize_t fruit_pread_meta(vfs_handle_struct *handle, > return -1; > } > >+ if (nread == -1 && fio->created) { >+ AfpInfo *ai = NULL; >+ char afpinfo_buf[AFP_INFO_SIZE]; >+ >+ ai = afpinfo_new(talloc_tos()); >+ if (ai == NULL) { >+ return -1; >+ } >+ >+ nread = afpinfo_pack(ai, afpinfo_buf); >+ TALLOC_FREE(ai); >+ if (nread != AFP_INFO_SIZE) { >+ return -1; >+ } >+ >+ memcpy(data, afpinfo_buf, to_return); >+ return nread; >+ } >+ > return nread; > } > >-- >2.17.2 > > >From 932a4b841b5ed78d7037441e5471448f1546b084 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Aug 2018 16:49:23 +0200 >Subject: [PATCH 38/43] vfs_fruit: do ino calculation > >As we'll start returning fake fds in open shortly, we can't rely on the >next module to calculat correct inode numbers for streams and must take >over that responsibility. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 50 +++++++++++++++++++++++++++++++++++-- > 1 file changed, 48 insertions(+), 2 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 5dbdeedab89..1e6ceb0e8f0 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -4898,6 +4898,14 @@ static int fruit_stat_meta_stream(vfs_handle_struct *handle, > bool follow_links) > { > int ret; >+ ino_t ino; >+ >+ ret = fruit_stat_base(handle, smb_fname, false); >+ if (ret != 0) { >+ return -1; >+ } >+ >+ ino = fruit_inode(&smb_fname->st, smb_fname->stream_name); > > if (follow_links) { > ret = SMB_VFS_NEXT_STAT(handle, smb_fname); >@@ -4905,6 +4913,8 @@ static int fruit_stat_meta_stream(vfs_handle_struct *handle, > ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); > } > >+ smb_fname->st.st_ex_ino = ino; >+ > return ret; > } > >@@ -5158,7 +5168,41 @@ static int fruit_fstat_meta_stream(vfs_handle_struct *handle, > files_struct *fsp, > SMB_STRUCT_STAT *sbuf) > { >- return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); >+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); >+ ino_t ino; >+ int ret; >+ >+ if (fio == NULL) { >+ return -1; >+ } >+ >+ if (fio->fake_fd) { >+ ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false); >+ if (ret != 0) { >+ return -1; >+ } >+ >+ *sbuf = fsp->base_fsp->fsp_name->st; >+ sbuf->st_ex_size = AFP_INFO_SIZE; >+ sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name); >+ return 0; >+ } >+ >+ ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false); >+ if (ret != 0) { >+ return -1; >+ } >+ *sbuf = fsp->base_fsp->fsp_name->st; >+ >+ ino = fruit_inode(sbuf, fsp->fsp_name->stream_name); >+ >+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); >+ if (ret != 0) { >+ return -1; >+ } >+ >+ sbuf->st_ex_ino = ino; >+ return 0; > } > > static int fruit_fstat_meta_netatalk(vfs_handle_struct *handle, >@@ -5393,12 +5437,14 @@ static NTSTATUS fruit_streaminfo_meta_stream( > goto out; > } > >- ret = SMB_VFS_NEXT_STAT(handle, sname); >+ ret = fruit_stat_base(handle, sname, false); > if (ret != 0) { > status = map_nt_error_from_unix(errno); > goto out; > } > >+ sname->st.st_ex_ino = fruit_inode(&sname->st, AFPINFO_STREAM); >+ > id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sname->st); > > lck = get_existing_share_mode_lock(talloc_tos(), id); >-- >2.17.2 > > >From f627dc0975d928b3d509681f4766415f69f6bf82 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 17 Oct 2018 16:51:34 +0200 >Subject: [PATCH 39/43] vfs_fruit: let fruit handle all aio on the FinderInfo > metadata stream > >This will be required to support using fake fds for the FinderInfo >metadata stream. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 4 +--- > 1 file changed, 1 insertion(+), 3 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 1e6ceb0e8f0..440be3ffe04 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -4416,9 +4416,7 @@ static bool fruit_must_handle_aio_stream(struct fio *fio) > return false; > }; > >- if ((fio->type == ADOUBLE_META) && >- (fio->config->meta == FRUIT_META_NETATALK)) >- { >+ if (fio->type == ADOUBLE_META) { > return true; > } > >-- >2.17.2 > > >From 6a803a2345db9fc2ba1940954298e82a8b10fd4e Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 23:46:43 +0200 >Subject: [PATCH 40/43] vfs_fruit: pass stream size to > delete_invalid_meta_stream() > >delete_invalid_meta_stream() is meant to guard against random data being >present in the FinderInfo stream. If the stream size is 0, it's likely a >freshly created stream where no data has been written to yet, so don't >delete it. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 15 ++++++++++++--- > 1 file changed, 12 insertions(+), 3 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 440be3ffe04..f486a0589e7 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5352,7 +5352,8 @@ static NTSTATUS delete_invalid_meta_stream( > const struct smb_filename *smb_fname, > TALLOC_CTX *mem_ctx, > unsigned int *pnum_streams, >- struct stream_struct **pstreams) >+ struct stream_struct **pstreams, >+ off_t size) > { > struct smb_filename *sname = NULL; > int ret; >@@ -5363,6 +5364,10 @@ static NTSTATUS delete_invalid_meta_stream( > return NT_STATUS_INTERNAL_ERROR; > } > >+ if (size == 0) { >+ return NT_STATUS_OK; >+ } >+ > sname = synthetic_smb_fname(talloc_tos(), > smb_fname->base_name, > AFPINFO_STREAM_NAME, >@@ -5416,8 +5421,12 @@ static NTSTATUS fruit_streaminfo_meta_stream( > DBG_ERR("Removing invalid AFPINFO_STREAM size [%jd] from [%s]\n", > (intmax_t)stream[i].size, smb_fname_str_dbg(smb_fname)); > >- return delete_invalid_meta_stream(handle, smb_fname, mem_ctx, >- pnum_streams, pstreams); >+ return delete_invalid_meta_stream(handle, >+ smb_fname, >+ mem_ctx, >+ pnum_streams, >+ pstreams, >+ stream[i].size); > } > > /* >-- >2.17.2 > > >From 38ce75c2f85d874deeec25b8b5afd5442abf9c39 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 23:40:14 +0200 >Subject: [PATCH 41/43] vfs_fruit: let fruit_pwrite_meta_stream also ftruncate > empty FinderInfo > >fruit_streaminfo currently filters out the FinderInfo stream is >delete-on-close is set. We set it here internally, but the client may >also set it over SMB. Turns out that the macOS SMB server does NOT >filter out FinderInfo stream with delete-on-close set, so we must change >the way filtering is done in fruit_streaminfo. > >Filtering is now done based on the FinderInfo stream being 0-bytes large which >is why I'm adding the ftruncate here. > >No idea why the tests that check the filtering passed the commits >leading up to this one, but if you revert this commit after applying the >whole patchset, the "delete AFP_AfpInfo by writing all 0" test will fail. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 30 ++++++++++++++++++------------ > 1 file changed, 18 insertions(+), 12 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index f486a0589e7..34b7f25c99b 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -4554,23 +4554,29 @@ static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle, > return -1; > } > >- nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); >- if (nwritten != n) { >- return -1; >- } >- >- if (!ai_empty_finderinfo(ai)) { >- return n; >- } >+ if (ai_empty_finderinfo(ai)) { >+ ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, 0); >+ if (ret != 0) { >+ DBG_ERR("SMB_VFS_NEXT_FTRUNCATE on [%s] failed\n", >+ fsp_str_dbg(fsp)); >+ return -1; >+ } > >- ok = set_delete_on_close( >+ ok = set_delete_on_close( > fsp, > true, > handle->conn->session_info->security_token, > handle->conn->session_info->unix_token); >- if (!ok) { >- DBG_ERR("set_delete_on_close on [%s] failed\n", >- fsp_str_dbg(fsp)); >+ if (!ok) { >+ DBG_ERR("set_delete_on_close on [%s] failed\n", >+ fsp_str_dbg(fsp)); >+ return -1; >+ } >+ return n; >+ } >+ >+ nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); >+ if (nwritten != n) { > return -1; > } > >-- >2.17.2 > > >From e4f7973f660aadfe000cd92f0c96ba99d813369e Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Sat, 20 Oct 2018 23:50:32 +0200 >Subject: [PATCH 42/43] vfs_fruit: don't check for delete-on-close on the > FinderInfo stream > >macOS SMB server doesn't filter out the FinderInfo stream if it has >delete-on-close set. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > source3/modules/vfs_fruit.c | 73 +------------------------------------ > 1 file changed, 1 insertion(+), 72 deletions(-) > >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 34b7f25c99b..4f3db64a681 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -5402,16 +5402,7 @@ static NTSTATUS fruit_streaminfo_meta_stream( > { > struct stream_struct *stream = *pstreams; > unsigned int num_streams = *pnum_streams; >- struct smb_filename *sname = NULL; >- char *full_name = NULL; >- uint32_t name_hash; >- struct share_mode_lock *lck = NULL; >- struct file_id id = {0}; >- bool delete_on_close_set; > int i; >- int ret; >- NTSTATUS status; >- bool ok; > > for (i = 0; i < num_streams; i++) { > if (strequal_m(stream[i].name, AFPINFO_STREAM)) { >@@ -5435,70 +5426,8 @@ static NTSTATUS fruit_streaminfo_meta_stream( > stream[i].size); > } > >- /* >- * Now check if there's a delete-on-close pending on the stream. If so, >- * hide the stream. This behaviour was verified against a macOS 10.12 >- * SMB server. >- */ > >- sname = synthetic_smb_fname(talloc_tos(), >- smb_fname->base_name, >- AFPINFO_STREAM_NAME, >- NULL, 0); >- if (sname == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto out; >- } >- >- ret = fruit_stat_base(handle, sname, false); >- if (ret != 0) { >- status = map_nt_error_from_unix(errno); >- goto out; >- } >- >- sname->st.st_ex_ino = fruit_inode(&sname->st, AFPINFO_STREAM); >- >- id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sname->st); >- >- lck = get_existing_share_mode_lock(talloc_tos(), id); >- if (lck == NULL) { >- status = NT_STATUS_OK; >- goto out; >- } >- >- full_name = talloc_asprintf(talloc_tos(), >- "%s%s", >- sname->base_name, >- AFPINFO_STREAM); >- if (full_name == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto out; >- } >- >- status = file_name_hash(handle->conn, full_name, &name_hash); >- if (!NT_STATUS_IS_OK(status)) { >- goto out; >- } >- >- delete_on_close_set = is_delete_on_close_set(lck, name_hash); >- if (delete_on_close_set) { >- ok = del_fruit_stream(mem_ctx, >- pnum_streams, >- pstreams, >- AFPINFO_STREAM); >- if (!ok) { >- status = NT_STATUS_INTERNAL_ERROR; >- goto out; >- } >- } >- >- status = NT_STATUS_OK; >- >-out: >- TALLOC_FREE(sname); >- TALLOC_FREE(lck); >- TALLOC_FREE(full_name); >- return status; >+ return NT_STATUS_OK; > } > > static NTSTATUS fruit_streaminfo_meta_netatalk( >-- >2.17.2 > > >From b95b733217fb63c105e90e6c5e984793ebf76a29 Mon Sep 17 00:00:00 2001 >From: Ralph Boehme <slow@samba.org> >Date: Wed, 22 Aug 2018 15:25:26 +0200 >Subject: [PATCH 43/43] vfs_fruit: let fruit_open_meta() with O_CREAT return a > fake-fd > >This is the final step in implementing the needed macOS semantics on the >FinderInfo stream: as long as the client hasn't written a non-zero >FinderInfo blob to the stream, there mustn't be a visible filesystem >entry for other openers. > >Bug: https://bugzilla.samba.org/show_bug.cgi?id=13646 > >Signed-off-by: Ralph Boehme <slow@samba.org> >--- > selftest/knownfail.d/samba3.vfs.fruit | 3 - > source3/modules/vfs_fruit.c | 165 +++++++++++--------------- > 2 files changed, 72 insertions(+), 96 deletions(-) > >diff --git a/selftest/knownfail.d/samba3.vfs.fruit b/selftest/knownfail.d/samba3.vfs.fruit >index 2d3c21caf91..6307e2b3404 100644 >--- a/selftest/knownfail.d/samba3.vfs.fruit >+++ b/selftest/knownfail.d/samba3.vfs.fruit >@@ -1,5 +1,2 @@ > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion\(nt4_dc\) > ^samba3.vfs.fruit streams_depot.OS X AppleDouble file conversion without embedded xattr\(nt4_dc\) >-^samba3.vfs.fruit metadata_netatalk.empty_stream\(nt4_dc\) >-^samba3.vfs.fruit metadata_stream.empty_stream\(nt4_dc\) >-^samba3.vfs.fruit streams_depot.empty_stream\(nt4_dc\) >diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c >index 4f3db64a681..dd1aa123104 100644 >--- a/source3/modules/vfs_fruit.c >+++ b/source3/modules/vfs_fruit.c >@@ -3403,66 +3403,68 @@ static int fruit_connect(vfs_handle_struct *handle, > return rc; > } > >+static int fruit_fake_fd(void) >+{ >+ int pipe_fds[2]; >+ int fd; >+ int ret; >+ >+ /* >+ * Return a valid fd, but ensure any attempt to use it returns >+ * an error (EPIPE). Once we get a write on the handle, we open >+ * the real fd. >+ */ >+ ret = pipe(pipe_fds); >+ if (ret != 0) { >+ return -1; >+ } >+ fd = pipe_fds[0]; >+ close(pipe_fds[1]); >+ >+ return fd; >+} >+ > static int fruit_open_meta_stream(vfs_handle_struct *handle, > struct smb_filename *smb_fname, > files_struct *fsp, > int flags, > mode_t mode) > { >- AfpInfo *ai = NULL; >- char afpinfo_buf[AFP_INFO_SIZE]; >- ssize_t len, written; >- int hostfd = -1; >- int rc = -1; >+ struct fruit_config_data *config = NULL; >+ struct fio *fio = NULL; >+ int open_flags = flags & ~O_CREAT; >+ int fd; > >- hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); >- if (hostfd == -1) { >- return -1; >- } >+ DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname)); > >- if (!(flags & (O_CREAT | O_TRUNC))) { >- return hostfd; >- } >+ SMB_VFS_HANDLE_GET_DATA(handle, config, >+ struct fruit_config_data, return -1); > >- ai = afpinfo_new(talloc_tos()); >- if (ai == NULL) { >- rc = -1; >- goto fail; >- } >+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL); >+ fio->type = ADOUBLE_META; >+ fio->config = config; > >- len = afpinfo_pack(ai, afpinfo_buf); >- if (len != AFP_INFO_SIZE) { >- rc = -1; >- goto fail; >+ fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, open_flags, mode); >+ if (fd != -1) { >+ return fd; > } > >- /* Set fd, needed in SMB_VFS_NEXT_PWRITE() */ >- fsp->fh->fd = hostfd; >- >- written = SMB_VFS_NEXT_PWRITE(handle, fsp, afpinfo_buf, >- AFP_INFO_SIZE, 0); >- fsp->fh->fd = -1; >- if (written != AFP_INFO_SIZE) { >- DBG_ERR("bad write [%zd/%d]\n", written, AFP_INFO_SIZE); >- rc = -1; >- goto fail; >+ if (!(flags & O_CREAT)) { >+ VFS_REMOVE_FSP_EXTENSION(handle, fsp); >+ return -1; > } > >- rc = 0; >+ fd = fruit_fake_fd(); >+ if (fd == -1) { >+ VFS_REMOVE_FSP_EXTENSION(handle, fsp); >+ return -1; >+ } > >-fail: >- DBG_DEBUG("rc=%d, fd=%d\n", rc, hostfd); >+ fio->fake_fd = true; >+ fio->flags = flags; >+ fio->mode = mode; > >- if (rc != 0) { >- int saved_errno = errno; >- if (hostfd >= 0) { >- fsp->fh->fd = hostfd; >- SMB_VFS_NEXT_CLOSE(handle, fsp); >- } >- hostfd = -1; >- errno = saved_errno; >- } >- return hostfd; >+ return fd; > } > > static int fruit_open_meta_netatalk(vfs_handle_struct *handle, >@@ -3471,56 +3473,42 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle, > int flags, > mode_t mode) > { >- int rc; >- int fakefd = -1; >+ struct fruit_config_data *config = NULL; >+ struct fio *fio = NULL; > struct adouble *ad = NULL; >- int fds[2]; >+ bool meta_exists = false; >+ int fd; > > DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname)); > >- /* >- * Return a valid fd, but ensure any attempt to use it returns an error >- * (EPIPE). All operations on the smb_fname or the fsp will use path >- * based syscalls. >- */ >- rc = pipe(fds); >- if (rc != 0) { >- goto exit; >+ ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META); >+ if (ad != NULL) { >+ meta_exists = true; > } >- fakefd = fds[0]; >- close(fds[1]); >- >- if (flags & (O_CREAT | O_TRUNC)) { >- /* >- * The attribute does not exist or needs to be truncated, >- * create an AppleDouble EA >- */ >- ad = ad_init(fsp, handle, ADOUBLE_META); >- if (ad == NULL) { >- rc = -1; >- goto exit; >- } > >- rc = ad_set(ad, fsp->fsp_name); >- if (rc != 0) { >- rc = -1; >- goto exit; >- } >+ TALLOC_FREE(ad); > >- TALLOC_FREE(ad); >+ if (!meta_exists && !(flags & O_CREAT)) { >+ errno = ENOENT; >+ return -1; > } > >-exit: >- DEBUG(10, ("fruit_open meta rc=%d, fd=%d\n", rc, fakefd)); >- if (rc != 0) { >- int saved_errno = errno; >- if (fakefd >= 0) { >- close(fakefd); >- } >- fakefd = -1; >- errno = saved_errno; >+ fd = fruit_fake_fd(); >+ if (fd == -1) { >+ return -1; > } >- return fakefd; >+ >+ SMB_VFS_HANDLE_GET_DATA(handle, config, >+ struct fruit_config_data, return -1); >+ >+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL); >+ fio->type = ADOUBLE_META; >+ fio->config = config; >+ fio->fake_fd = true; >+ fio->flags = flags; >+ fio->mode = mode; >+ >+ return fd; > } > > static int fruit_open_meta(vfs_handle_struct *handle, >@@ -3529,7 +3517,6 @@ static int fruit_open_meta(vfs_handle_struct *handle, > { > int fd; > struct fruit_config_data *config = NULL; >- struct fio *fio = NULL; > > DBG_DEBUG("path [%s]\n", smb_fname_str_dbg(smb_fname)); > >@@ -3554,14 +3541,6 @@ static int fruit_open_meta(vfs_handle_struct *handle, > > DBG_DEBUG("path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd); > >- if (fd == -1) { >- return -1; >- } >- >- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL); >- fio->type = ADOUBLE_META; >- fio->config = config; >- > return fd; > } > >-- >2.17.2 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 13646
:
14514
|
14544
|
14545
|
14546
|
14556
|
14557
|
14558
|
14559
|
14561
|
14562