[SCM] Samba Shared Repository - branch v4-3-test updated
Karolin Seeger
kseeger at samba.org
Fri Sep 4 13:46:02 UTC 2015
The branch, v4-3-test has been updated
via c581152 s4:torture:vfs_fruit: created empty resourceforks
via 2c67478 s4:torture:vfs_fruit: add a resource fork truncation test
via d282460 vfs_fruit: delete ._ file when deleting the basefile
via 05e8017 vfs_fruit: split and simplify fruit_ftruncate
via 6c10925 vfs_fruit: handling of empty resource fork
from 0befbeb samr4: Use <SID=%s> in GetGroupsForUser
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-3-test
- Log -----------------------------------------------------------------
commit c581152c09fe1e15efacd6f7a3561abf402a2493
Author: Ralph Boehme <slow at samba.org>
Date: Fri Aug 7 15:48:33 2015 +0200
s4:torture:vfs_fruit: created empty resourceforks
Check for opens and creates, created empty resourceforks result in
ENOENT in subsequent opens.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11467
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Autobuild-User(master): Jeremy Allison <jra at samba.org>
Autobuild-Date(master): Wed Sep 2 06:50:16 CEST 2015 on sn-devel-104
Autobuild-User(v4-3-test): Karolin Seeger <kseeger at samba.org>
Autobuild-Date(v4-3-test): Fri Sep 4 15:45:15 CEST 2015 on sn-devel-104
commit 2c6747866ac61697d61e758aa0aff83af28ba0d1
Author: Ralph Boehme <slow at samba.org>
Date: Thu Aug 6 11:32:29 2015 +0200
s4:torture:vfs_fruit: add a resource fork truncation test
Truncating a resource fork to 0 bytes should make it inaccessible for
subsequent creates and return NT_STATUS_OBJECT_NAME_NOT_FOUND.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11467
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit d28246057c80e2c8233d24412a272c9c3425e1a5
Author: Ralph Boehme <slow at samba.org>
Date: Tue Aug 25 17:06:52 2015 +0200
vfs_fruit: delete ._ file when deleting the basefile
0 byte resource fork streams are not listed by vfs_streaminfo, as a
result stream cleanup/deletion of file deletion doesn't remove the
resourcefork stream.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11467
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 05e80175fb85faf048d0d36a3972c8e0f8710cb4
Author: Ralph Boehme <slow at samba.org>
Date: Wed Aug 12 07:34:53 2015 +0200
vfs_fruit: split and simplify fruit_ftruncate
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11467
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 6c109257df8aa95f503fc6ee4166753c3ac250b4
Author: Ralph Boehme <slow at samba.org>
Date: Sat Aug 8 20:21:39 2015 +0200
vfs_fruit: handling of empty resource fork
Opening the resource fork stream with O_CREAT mustn't create a visible
node in the filesystem, only create a file handle. As long as the
creator didn't write into the stream, other openers withour O_CREAT
MUST get an ENOENT error. This is way OS X SMB server implements it.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11467
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
-----------------------------------------------------------------------
Summary of changes:
source3/modules/vfs_fruit.c | 186 ++++++++++++++++++++++++---------
source4/torture/vfs/fruit.c | 247 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 383 insertions(+), 50 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 8ac4ba1..21b49f9 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -2389,15 +2389,44 @@ static int fruit_unlink(vfs_handle_struct *handle,
{
int rc = -1;
struct fruit_config_data *config = NULL;
- char *adp = NULL;
-
- if (!is_ntfs_stream_smb_fname(smb_fname)) {
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
- }
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
+ if (!is_ntfs_stream_smb_fname(smb_fname)) {
+ char *adp = NULL;
+
+ rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+ if (rc != 0) {
+ return -1;
+ }
+
+ if (config->rsrc != FRUIT_RSRC_ADFILE) {
+ return 0;
+ }
+
+ /*
+ * 0 byte resource fork streams are not listed by
+ * vfs_streaminfo, as a result stream cleanup/deletion of file
+ * deletion doesn't remove the resourcefork stream.
+ */
+ rc = adouble_path(talloc_tos(),
+ smb_fname->base_name, &adp);
+ if (rc != 0) {
+ return -1;
+ }
+
+ /* FIXME: direct unlink(), missing smb_fname */
+ DEBUG(1,("fruit_unlink: %s\n", adp));
+ rc = unlink(adp);
+ if ((rc == -1) && (errno == ENOENT)) {
+ rc = 0;
+ }
+
+ TALLOC_FREE(adp);
+ return 0;
+ }
+
if (is_afpinfo_stream(smb_fname)) {
if (config->meta == FRUIT_META_STREAM) {
rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
@@ -2406,8 +2435,14 @@ static int fruit_unlink(vfs_handle_struct *handle,
smb_fname->base_name,
AFPINFO_EA_NETATALK);
}
- } else if (is_afpresource_stream(smb_fname)) {
+
+ return rc;
+ }
+
+ if (is_afpresource_stream(smb_fname)) {
if (config->rsrc == FRUIT_RSRC_ADFILE) {
+ char *adp = NULL;
+
rc = adouble_path(talloc_tos(),
smb_fname->base_name, &adp);
if (rc != 0) {
@@ -2418,17 +2453,20 @@ static int fruit_unlink(vfs_handle_struct *handle,
if ((rc == -1) && (errno == ENOENT)) {
rc = 0;
}
+ TALLOC_FREE(adp);
} else {
rc = SMB_VFS_REMOVEXATTR(handle->conn,
- smb_fname->base_name,
- AFPRESOURCE_EA_NETATALK);
+ smb_fname->base_name,
+ AFPRESOURCE_EA_NETATALK);
}
- } else {
- rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+
+ return rc;
}
- TALLOC_FREE(adp);
- return rc;
+ return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+
+
+ return 0;
}
static int fruit_chmod(vfs_handle_struct *handle,
@@ -3085,7 +3123,7 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
if (config->rsrc != FRUIT_RSRC_STREAM) {
ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
ADOUBLE_RSRC);
- if (ad) {
+ if (ad && (ad_getentrylen(ad, ADEID_RFORK) > 0)) {
if (!add_fruit_stream(
mem_ctx, pnum_streams, pstreams,
AFPRESOURCE_STREAM_NAME,
@@ -3163,6 +3201,62 @@ static int fruit_fallocate(struct vfs_handle_struct *handle,
return -1;
}
+static int fruit_ftruncate_meta(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ off_t offset,
+ struct adouble *ad)
+{
+ /*
+ * As this request hasn't been seen in the wild,
+ * the only sensible use I can imagine is the client
+ * truncating the stream to 0 bytes size.
+ * We simply remove the metadata on such a request.
+ */
+ if (offset != 0) {
+ DBG_WARNING("ftruncate %s to %jd",
+ fsp_str_dbg(fsp), (intmax_t)offset);
+ return -1;
+ }
+
+ return SMB_VFS_FREMOVEXATTR(fsp, AFPRESOURCE_EA_NETATALK);
+}
+
+static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ off_t offset,
+ struct adouble *ad)
+{
+ int rc;
+ struct fruit_config_data *config;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct fruit_config_data, return -1);
+
+ if (config->rsrc == FRUIT_RSRC_XATTR && offset == 0) {
+ return SMB_VFS_FREMOVEXATTR(fsp,
+ AFPRESOURCE_EA_NETATALK);
+ }
+
+ rc = SMB_VFS_NEXT_FTRUNCATE(
+ handle, fsp,
+ offset + ad_getentryoff(ad, ADEID_RFORK));
+ if (rc != 0) {
+ return -1;
+ }
+
+ if (config->rsrc == FRUIT_RSRC_ADFILE) {
+ ad_setentrylen(ad, ADEID_RFORK, offset);
+ rc = ad_write(ad, NULL);
+ if (rc != 0) {
+ return -1;
+ }
+ DEBUG(10, ("fruit_ftruncate_rsrc file %s offset %jd\n",
+ fsp_str_dbg(fsp), (intmax_t)offset));
+ }
+
+ return 0;
+}
+
static int fruit_ftruncate(struct vfs_handle_struct *handle,
struct files_struct *fsp,
off_t offset)
@@ -3170,7 +3264,6 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle,
int rc = 0;
struct adouble *ad =
(struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
- struct fruit_config_data *config;
DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
fsp_str_dbg(fsp), (double)offset));
@@ -3183,40 +3276,15 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle,
return -1;
}
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct fruit_config_data, return -1);
-
switch (ad->ad_type) {
case ADOUBLE_META:
- /*
- * As this request hasn't been seen in the wild,
- * the only sensible use I can imagine is the client
- * truncating the stream to 0 bytes size.
- * We simply remove the metadata on such a request.
- */
- if (offset == 0) {
- rc = SMB_VFS_FREMOVEXATTR(fsp,
- AFPRESOURCE_EA_NETATALK);
- }
+ rc = fruit_ftruncate_meta(handle, fsp, offset, ad);
break;
+
case ADOUBLE_RSRC:
- if (config->rsrc == FRUIT_RSRC_XATTR && offset == 0) {
- rc = SMB_VFS_FREMOVEXATTR(fsp,
- AFPRESOURCE_EA_NETATALK);
- } else {
- rc = SMB_VFS_NEXT_FTRUNCATE(
- handle, fsp,
- offset + ad_getentryoff(ad, ADEID_RFORK));
- if (rc != 0) {
- return -1;
- }
- ad_setentrylen(ad, ADEID_RFORK, offset);
- rc = ad_write(ad, NULL);
- if (rc != 0) {
- return -1;
- }
- }
+ rc = fruit_ftruncate_rsrc(handle, fsp, offset, ad);
break;
+
default:
return -1;
}
@@ -3246,6 +3314,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
{
NTSTATUS status;
struct fruit_config_data *config = NULL;
+ files_struct *fsp = NULL;
status = check_aapl(handle, req, in_context_blobs, out_context_blobs);
if (!NT_STATUS_IS_OK(status)) {
@@ -3267,6 +3336,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ fsp = *result;
if (config->copyfile_enabled) {
/*
@@ -3275,11 +3345,27 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
* for copychunk should be allowed in a copychunk
* request with a count of 0.
*/
- (*result)->aapl_copyfile_supported = true;
+ fsp->aapl_copyfile_supported = true;
+ }
+
+ /*
+ * If this is a plain open for existing files, opening an 0
+ * byte size resource fork MUST fail with
+ * NT_STATUS_OBJECT_NAME_NOT_FOUND.
+ *
+ * Cf the vfs_fruit torture tests in test_rfork_create().
+ */
+ if (is_afpresource_stream(fsp->fsp_name) &&
+ create_disposition == FILE_OPEN)
+ {
+ if (fsp->fsp_name->st.st_ex_size == 0) {
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ goto fail;
+ }
}
+
if (is_ntfs_stream_smb_fname(smb_fname)
- || (*result == NULL)
- || ((*result)->is_directory)) {
+ || fsp->is_directory) {
return status;
}
@@ -3296,11 +3382,11 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
return status;
fail:
- DEBUG(1, ("fruit_create_file: %s\n", nt_errstr(status)));
+ DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
- if (*result) {
- close_file(req, *result, ERROR_CLOSE);
- *result = NULL;
+ if (fsp) {
+ close_file(req, fsp, ERROR_CLOSE);
+ *result = fsp = NULL;
}
return status;
diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c
index a74dd7d..1c1d4ad 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -59,6 +59,13 @@
goto done; \
}} while (0)
+static bool check_stream_list(struct smb2_tree *tree,
+ struct torture_context *tctx,
+ const char *fname,
+ int num_exp,
+ const char **exp,
+ struct smb2_handle h);
+
static int qsort_string(char * const *s1, char * const *s2)
{
return strcmp(*s1, *s2);
@@ -1421,6 +1428,244 @@ done:
return ret;
}
+static bool test_rfork_truncate(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_truncate";
+ const char *rfork = BASEDIR "\\torture_rfork_truncate" AFPRESOURCE_STREAM;
+ const char *rfork_content = "1234567890";
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle fh1, fh2, fh3;
+ union smb_setfileinfo sinfo;
+
+ smb2_util_unlink(tree1, fname);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree1, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree1, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ ret &= write_stream(tree1, __location__, tctx, mem_ctx,
+ fname, AFPRESOURCE_STREAM,
+ 10, 10, rfork_content);
+
+ /* Truncate back to size 0, further access MUST return ENOENT */
+
+ torture_comment(tctx, "(%s) truncate resource fork to size 0\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = fname;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh1 = create.out.file.handle;
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh2 = create.out.file.handle;
+
+ ZERO_STRUCT(sinfo);
+ sinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sinfo.end_of_file_info.in.file.handle = fh2;
+ sinfo.end_of_file_info.in.size = 0;
+ status = smb2_setinfo_file(tree1, &sinfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file");
+
+ /*
+ * Now check size, we should get OBJECT_NAME_NOT_FOUND (!)
+ */
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+ /*
+ * Do another open on the rfork and write to the new handle. A
+ * naive server might unlink the AppleDouble resource fork
+ * file when its truncated to 0 bytes above, so in case both
+ * open handles share the same underlying fd, the unlink would
+ * cause the below write to be lost.
+ */
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh3 = create.out.file.handle;
+
+ status = smb2_util_write(tree1, fh3, "foo", 0, 3);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write");
+
+ smb2_util_close(tree1, fh3);
+ smb2_util_close(tree1, fh2);
+ smb2_util_close(tree1, fh1);
+
+ ret = check_stream(tree1, __location__, tctx, mem_ctx, fname, AFPRESOURCE_STREAM,
+ 0, 3, 0, 3, "foo");
+ torture_assert_goto(tctx, ret == true, ret, done, "check_stream");
+
+done:
+ smb2_util_unlink(tree1, fname);
+ smb2_deltree(tree1, BASEDIR);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static bool test_rfork_create(struct torture_context *tctx,
+ struct smb2_tree *tree1,
+ struct smb2_tree *tree2)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ const char *fname = BASEDIR "\\torture_rfork_create";
+ const char *rfork = BASEDIR "\\torture_rfork_create" AFPRESOURCE_STREAM;
+ NTSTATUS status;
+ struct smb2_handle testdirh;
+ bool ret = true;
+ struct smb2_create create;
+ struct smb2_handle fh1;
+ const char *streams[] = {
+ "::$DATA"
+ };
+ union smb_fileinfo finfo;
+
+ smb2_util_unlink(tree1, fname);
+
+ status = torture_smb2_testdir(tree1, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir");
+ smb2_util_close(tree1, testdirh);
+
+ ret = torture_setup_file(mem_ctx, tree1, fname, false);
+ if (ret == false) {
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) open rfork, should return ENOENT\n",
+ __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, ret, done, "smb2_create");
+
+ torture_comment(tctx, "(%s) create resource fork\n", __location__);
+
+ ZERO_STRUCT(create);
+ create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+ create.in.desired_access = SEC_STD_READ_CONTROL | SEC_FILE_ALL;
+ create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
+ create.in.fname = rfork;
+ create.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE |
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = smb2_create(tree1, mem_ctx, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create");
+ fh1 = create.out.file.handle;
+
+ torture_comment(tctx, "(%s) getinfo on create handle\n",
+ __location__);
+
+ ZERO_STRUCT(finfo);
+ finfo.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ finfo.generic.in.file.handle = fh1;
+ status = smb2_getinfo_file(tree1, mem_ctx, &finfo);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file");
+ if (finfo.all_info.out.size != 0) {
+ torture_result(tctx, TORTURE_FAIL,
+ "(%s) Incorrect resource fork size\n",
+ __location__);
+ ret = false;
+ smb2_util_close(tree1, fh1);
+ goto done;
+ }
+
+ torture_comment(tctx, "(%s) open rfork, should still return ENOENT\n",
+ __location__);
+
--
Samba Shared Repository
More information about the samba-cvs
mailing list