[Pkg-samba-maint] [samba] 10/17: Revert "vfs_fruit: fix fruit:resource option spelling, but not behaviour"

Mathieu Parent sathieu at moszumanska.debian.org
Mon Mar 6 11:50:06 UTC 2017


This is an automated email from the git hooks/post-receive script.

sathieu pushed a commit to branch master
in repository samba.

commit 4387d85db3c9e4508b49ebe61534c696b93638b5
Author: Karolin Seeger <kseeger at samba.org>
Date:   Fri Jan 27 05:37:20 2017 +0100

    Revert "vfs_fruit: fix fruit:resource option spelling, but not behaviour"
    
    This reverts commit 586f8b73b6c189cb825ce2e8817230ca57f87d35.
    
    This patchset slipped in by accident and is not in master yet.
    The commit message does not fit to the set of patches, because numerous patches
    have been squashed into one commit. It's a rewrite of vfs_fruit.
    Reverting until review will be finished and patches are in master.
    
    Autobuild-User(v4-5-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-5-test): Fri Jan 27 09:48:52 CET 2017 on sn-devel-144
---
 docs-xml/manpages/vfs_fruit.8.xml   |    8 +-
 lib/torture/torture.h               |   10 -
 selftest/target/Samba3.pm           |   26 +-
 selftest/target/Samba4.pm           |    2 +-
 source3/include/MacExtensions.h     |    3 -
 source3/modules/vfs_catia.c         | 1052 -----------
 source3/modules/vfs_fruit.c         | 3351 ++++++++++-------------------------
 source3/modules/vfs_streams_xattr.c |    6 +-
 source3/selftest/tests.py           |    7 +-
 source4/torture/vfs/fruit.c         |  398 +----
 source4/torture/vfs/vfs.c           |   37 +-
 11 files changed, 977 insertions(+), 3923 deletions(-)

diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml
index c31aa75..a0b3893 100644
--- a/docs-xml/manpages/vfs_fruit.8.xml
+++ b/docs-xml/manpages/vfs_fruit.8.xml
@@ -168,13 +168,9 @@
 
 	      <para>Controls how the set of illegal NTFS ASCII
 	      character, commonly used by OS X clients, are stored in
-	      the filesystem.</para>
+	      the filesystem:</para>
 
-	      <para><emphasis>Important:</emphasis> this is known to not fully
-	      work with <emphasis>fruit:metadata=stream</emphasis> or
-	      <emphasis>fruit:resource=stream</emphasis>.</para>
-
- 	      <itemizedlist>
+	      <itemizedlist>
 
 		<listitem><para><command>private (default)</command> -
 		store characters as encoded by the OS X client: mapped
diff --git a/lib/torture/torture.h b/lib/torture/torture.h
index f889211..45332b2 100644
--- a/lib/torture/torture.h
+++ b/lib/torture/torture.h
@@ -357,16 +357,6 @@ void torture_result(struct torture_context *test,
 	} \
 	} while(0)
 
-#define torture_assert_mem_equal_goto(torture_ctx,got,expected,len,ret,label,cmt) \
-	do { const void *__got = (got), *__expected = (expected); \
-	if (memcmp(__got, __expected, len) != 0) { \
-		torture_result(torture_ctx, TORTURE_FAIL, \
-			       __location__": "#got" of len %d did not match "#expected": %s", (int)len, cmt); \
-		return false; \
-		goto label; \
-	} \
-	} while(0)
-
 static inline void torture_dump_data_str_cb(const char *buf, void *private_data)
 {
 	char **dump = (char **)private_data;
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 9a06733..8f2a1f5 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1610,35 +1610,11 @@ sub provision($$$$$$$$)
 	path = $shrdir
 	vfs objects = catia fruit streams_xattr acl_xattr
 	ea support = yes
-	fruit:resource = file
+	fruit:ressource = file
 	fruit:metadata = netatalk
 	fruit:locking = netatalk
 	fruit:encoding = native
 
-[vfs_fruit_metadata_stream]
-	path = $shrdir
-	vfs objects = fruit streams_xattr acl_xattr
-	ea support = yes
-	fruit:resource = file
-	fruit:metadata = stream
-
-[vfs_fruit_stream_depot]
-	path = $shrdir
-	vfs objects = fruit streams_depot acl_xattr
-	ea support = yes
-	fruit:resource = stream
-	fruit:metadata = stream
-
-[vfs_wo_fruit]
-	path = $shrdir
-	vfs objects = streams_xattr acl_xattr
-	ea support = yes
-
-[vfs_wo_fruit_stream_depot]
-	path = $shrdir
-	vfs objects = streams_depot acl_xattr
-	ea support = yes
-
 [badname-tmp]
 	path = $badnames_shrdir
 	guest ok = yes
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index ffa104f..f1de4b9 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -910,7 +910,7 @@ sub provision($$$$$$$$$$)
 	path = $ctx->{share}
 	vfs objects = catia fruit streams_xattr acl_xattr
 	ea support = yes
-	fruit:resource = file
+	fruit:ressource = file
 	fruit:metadata = netatalk
 	fruit:locking = netatalk
 	fruit:encoding = native
diff --git a/source3/include/MacExtensions.h b/source3/include/MacExtensions.h
index e17d39b..23dcde9 100644
--- a/source3/include/MacExtensions.h
+++ b/source3/include/MacExtensions.h
@@ -51,9 +51,6 @@
 #define AFP_Version			0x00000100
 #define AFP_BackupTime		0x80000000
 #define AFP_FinderSize		32
-
-#define AFP_OFF_FinderInfo	16
-
 /*
 ** Orginal AFP_AfpInfo stream used by NT 
 ** We needed a way to store the create date so SAMBA
diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c
index 56d6447..f4c77d9 100644
--- a/source3/modules/vfs_catia.c
+++ b/source3/modules/vfs_catia.c
@@ -1114,1036 +1114,6 @@ catia_setxattr(vfs_handle_struct *handle, const char *path,
 	return ret;
 }
 
-static int catia_fstat(vfs_handle_struct *handle,
-		       files_struct *fsp,
-		       SMB_STRUCT_STAT *sbuf)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static ssize_t catia_pread(vfs_handle_struct *handle,
-			   files_struct *fsp, void *data,
-			   size_t n, off_t offset)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static ssize_t catia_pwrite(vfs_handle_struct *handle,
-			    files_struct *fsp, const void *data,
-			    size_t n, off_t offset)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_ftruncate(struct vfs_handle_struct *handle,
-			   struct files_struct *fsp,
-			   off_t offset)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_fallocate(struct vfs_handle_struct *handle,
-			   struct files_struct *fsp,
-			   uint32_t mode,
-			   off_t offset,
-			   off_t len)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static ssize_t catia_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	ssize_t result = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return result;
-}
-
-static ssize_t catia_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	ssize_t result = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return result;
-}
-
-static int catia_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle,
-				      files_struct *fsp,
-				      TALLOC_CTX *mem_ctx)
-{
-	struct smb_acl_t *result = NULL;
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return result;
-}
-
-static int catia_sys_acl_blob_get_fd(vfs_handle_struct *handle,
-				     files_struct *fsp,
-				     TALLOC_CTX *mem_ctx,
-				     char **blob_description,
-				     DATA_BLOB *blob)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
-					       blob_description, blob);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static NTSTATUS catia_fget_nt_acl(vfs_handle_struct *handle,
-				  files_struct *fsp,
-				  uint32_t security_info,
-				  TALLOC_CTX *mem_ctx,
-				  struct security_descriptor **ppdesc)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, mem_ctx, ppdesc);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return status;
-}
-
-static NTSTATUS catia_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return status;
-}
-
-static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle,
-					  struct files_struct *fsp,
-					  uint32_t dosmode)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return status;
-}
-
-static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle,
-					  struct files_struct *fsp,
-					  uint32_t *dosmode)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return status;
-}
-
-static int catia_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static int catia_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
-{
-	char *fname = NULL;
-	char *tmp_fname = NULL;
-	char *base_fname = NULL;
-	char *tmp_base_fname = NULL;
-	int ret = -1;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       fsp->fsp_name->base_name,
-					       &fname, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		goto done;
-	}
-
-	if (fsp->base_fsp != NULL) {
-		status = catia_string_replace_allocate(
-			handle->conn,
-			fsp->base_fsp->fsp_name->base_name,
-			&base_fname, vfs_translate_to_unix);
-		if (!NT_STATUS_IS_OK(status)) {
-			errno = map_errno_from_nt_status(status);
-			goto done;
-		}
-
-		tmp_base_fname = fsp->base_fsp->fsp_name->base_name;
-		fsp->base_fsp->fsp_name->base_name = base_fname;
-	}
-
-	tmp_fname = fsp->fsp_name->base_name;
-	fsp->fsp_name->base_name = fname;
-
-	ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
-
-	fsp->fsp_name->base_name = tmp_fname;
-	if (fsp->base_fsp != NULL) {
-		fsp->base_fsp->fsp_name->base_name = tmp_base_fname;
-	}
-
-done:
-	TALLOC_FREE(fname);
-	TALLOC_FREE(base_fname);
-
-	return ret;
-}
-
-static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle,
-				   const struct smb_filename *smb_fname_in,
-				   TALLOC_CTX *mem_ctx,
-				   struct readdir_attr_data **pattr_data)
-{
-	struct smb_filename *smb_fname;
-	char *fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-					       smb_fname_in->base_name,
-					       &fname,
-					       vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		return status;
-	}
-
-	smb_fname = synthetic_smb_fname(talloc_tos(), fname, NULL,
-					&smb_fname_in->st, 0);
-
-	status = SMB_VFS_NEXT_READDIR_ATTR(handle, smb_fname, mem_ctx, pattr_data);
-
-	TALLOC_FREE(smb_fname);
-	return status;
-}
-
-static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle,
-					 struct smb_filename *smb_fname,
-					 uint32_t *dosmode)
-{
-	char *mapped_name = NULL;
-	const char *path = smb_fname->base_name;
-	struct smb_filename *mapped_smb_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-				path, &mapped_name, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		return status;
-	}
-	mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
-					mapped_name,
-					NULL,
-					NULL,
-					smb_fname->flags);
-	if (mapped_smb_fname == NULL) {
-		TALLOC_FREE(mapped_name);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle,
-						 mapped_smb_fname,
-						 dosmode);
-	TALLOC_FREE(mapped_name);
-	TALLOC_FREE(mapped_smb_fname);
-
-	return status;
-}
-
-static NTSTATUS catia_set_dos_attributes(struct vfs_handle_struct *handle,
-					 const struct smb_filename *smb_fname,
-					 uint32_t dosmode)
-{
-	char *mapped_name = NULL;
-	const char *path = smb_fname->base_name;
-	struct smb_filename *mapped_smb_fname = NULL;
-	NTSTATUS status;
-
-	status = catia_string_replace_allocate(handle->conn,
-				path, &mapped_name, vfs_translate_to_unix);
-	if (!NT_STATUS_IS_OK(status)) {
-		errno = map_errno_from_nt_status(status);
-		return status;
-	}
-	mapped_smb_fname = synthetic_smb_fname(talloc_tos(),
-					mapped_name,
-					NULL,
-					NULL,
-					smb_fname->flags);
-	if (mapped_smb_fname == NULL) {
-		TALLOC_FREE(mapped_name);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle,
-						 mapped_smb_fname,
-						 dosmode);
-	TALLOC_FREE(mapped_name);
-	TALLOC_FREE(mapped_smb_fname);
-
-	return status;
-}
-
 static struct vfs_fn_pointers vfs_catia_fns = {
 	.mkdir_fn = catia_mkdir,
 	.rmdir_fn = catia_rmdir,
@@ -2171,28 +1141,6 @@ static struct vfs_fn_pointers vfs_catia_fns = {
 	.listxattr_fn = catia_listxattr,
 	.removexattr_fn = catia_removexattr,
 	.setxattr_fn = catia_setxattr,
-	.pread_fn = catia_pread,
-	.pwrite_fn = catia_pwrite,
-	.fstat_fn = catia_fstat,
-	.ftruncate_fn = catia_ftruncate,
-	.fallocate_fn = catia_fallocate,
-	.fgetxattr_fn = catia_fgetxattr,
-	.flistxattr_fn = catia_flistxattr,
-	.fremovexattr_fn = catia_fremovexattr,
-	.fsetxattr_fn = catia_fsetxattr,
-	.sys_acl_get_fd_fn = catia_sys_acl_get_fd,
-	.sys_acl_blob_get_fd_fn = catia_sys_acl_blob_get_fd,
-	.sys_acl_set_fd_fn = catia_sys_acl_set_fd,
-	.fchmod_acl_fn = catia_fchmod_acl,
-	.fget_nt_acl_fn = catia_fget_nt_acl,
-	.fset_nt_acl_fn = catia_fset_nt_acl,
-	.get_dos_attributes_fn = catia_get_dos_attributes,
-	.set_dos_attributes_fn = catia_set_dos_attributes,
-	.fset_dos_attributes_fn = catia_fset_dos_attributes,
-	.fget_dos_attributes_fn = catia_fget_dos_attributes,
-	.fchown_fn = catia_fchown,
-	.fchmod_fn = catia_fchmod,
-	.readdir_attr_fn = catia_readdir_attr,
 };
 
 static_decl_vfs;
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 12846b9..6e7899aa 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -68,7 +68,7 @@
  *
  * The AFP_Resource stream is stored in an AppleDouble file prepending
  * "._" to the filename. On Solaris with ZFS the stream is optionally
- * stored in an EA "org.netatalk.resource".
+ * stored in an EA "org.netatalk.ressource".
  *
  *
  * Extended Attributes
@@ -343,6 +343,7 @@ typedef enum {ADOUBLE_META, ADOUBLE_RSRC} adouble_type_t;
 #define ad_getentryoff(ad,eid)     ((ad)->ad_eid[(eid)].ade_off)
 #define ad_setentrylen(ad,eid,len) ((ad)->ad_eid[(eid)].ade_len = (len))
 #define ad_setentryoff(ad,eid,off) ((ad)->ad_eid[(eid)].ade_off = (off))
+#define ad_entry(ad,eid)           ((ad)->ad_data + ad_getentryoff((ad),(eid)))
 
 struct ad_entry {
 	size_t ade_off;
@@ -351,8 +352,7 @@ struct ad_entry {
 
 struct adouble {
 	vfs_handle_struct        *ad_handle;
-	int                       ad_fd;
-	bool                      ad_opened;
+	files_struct             *ad_fsp;
 	adouble_type_t            ad_type;
 	uint32_t                  ad_magic;
 	uint32_t                  ad_version;
@@ -378,7 +378,7 @@ struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
 	{0, 0, 0}
 };
 
-/* AppleDouble resource fork file (the ones prefixed by "._") */
+/* AppleDouble ressource fork file (the ones prefixed by "._") */
 static const
 struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
 	{ADEID_FINDERI,    ADEDOFF_FINDERI_DOT_UND,  ADEDLEN_FINDERI},
@@ -387,8 +387,8 @@ struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
 };
 
 /*
- * Fake AppleDouble entry oder for resource fork xattr.  The xattr
- * isn't an AppleDouble file, it simply contains the resource data,
+ * Fake AppleDouble entry oder for ressource fork xattr.  The xattr
+ * isn't an AppleDouble file, it simply contains the ressource data,
  * but in order to be able to use some API calls like ad_getentryoff()
  * we build a fake/helper struct adouble with this entry order struct.
  */
@@ -405,41 +405,15 @@ static const uint32_t set_eid[] = {
 	AD_DEV, AD_INO, AD_SYN, AD_ID
 };
 
-struct fio {
-	/* tcon config handle */
-	struct fruit_config_data *config;
-
-	/* Denote stream type, meta or rsrc */
-	adouble_type_t type;
-};
-
 /*
  * Forward declarations
  */
 static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle,
-			       adouble_type_t type);
-static int ad_set(struct adouble *ad, const char *path);
-static int ad_fset(struct adouble *ad, files_struct *fsp);
+			       adouble_type_t type, files_struct *fsp);
+static int ad_write(struct adouble *ad, const char *path);
 static int adouble_path(TALLOC_CTX *ctx, const char *path_in, char **path_out);
 
 /**
- * Return a pointer to an AppleDouble entry
- *
- * Returns NULL if the entry is not present
- **/
-static char *ad_get_entry(const struct adouble *ad, int eid)
-{
-	off_t off = ad_getentryoff(ad, eid);
-	size_t len = ad_getentrylen(ad, eid);
-
-	if (off == 0 || len == 0) {
-		return NULL;
-	}
-
-	return ad->ad_data + off;
-}
-
-/**
  * Get a date
  **/
 static int ad_getdate(const struct adouble *ad,
@@ -447,19 +421,18 @@ static int ad_getdate(const struct adouble *ad,
 		      uint32_t *date)
 {
 	bool xlate = (dateoff & AD_DATE_UNIX);
-	char *p = NULL;
 
 	dateoff &= AD_DATE_MASK;
-	p = ad_get_entry(ad, ADEID_FILEDATESI);
-	if (p == NULL) {
+	if (!ad_getentryoff(ad, ADEID_FILEDATESI)) {
 		return -1;
 	}
 
 	if (dateoff > AD_DATE_ACCESS) {
 	    return -1;
 	}
-
-	memcpy(date, p + dateoff, sizeof(uint32_t));
+	memcpy(date,
+	       ad_entry(ad, ADEID_FILEDATESI) + dateoff,
+	       sizeof(uint32_t));
 
 	if (xlate) {
 		*date = AD_DATE_TO_UNIX(*date);
@@ -473,11 +446,9 @@ static int ad_getdate(const struct adouble *ad,
 static int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
 {
 	bool xlate = (dateoff & AD_DATE_UNIX);
-	char *p = NULL;
 
-	p = ad_get_entry(ad, ADEID_FILEDATESI);
-	if (p == NULL) {
-		return -1;
+	if (!ad_getentryoff(ad, ADEID_FILEDATESI)) {
+		return 0;
 	}
 
 	dateoff &= AD_DATE_MASK;
@@ -489,7 +460,7 @@ static int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
 		return -1;
 	}
 
-	memcpy(p + dateoff, &date, sizeof(date));
+	memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date));
 
 	return 0;
 }
@@ -781,7 +752,7 @@ exit:
 /**
  * Read and parse Netatalk AppleDouble metadata xattr
  **/
-static ssize_t ad_read_meta(struct adouble *ad, const char *path)
+static ssize_t ad_header_read_meta(struct adouble *ad, const char *path)
 {
 	int      rc = 0;
 	ssize_t  ealen;
@@ -853,220 +824,184 @@ exit:
 	return ealen;
 }
 
-static int ad_open_meta(const char *path, int flags, mode_t mode)
-{
-	return open(path, flags, mode);
-}
-
-static int ad_open_rsrc_xattr(const char *path, int flags, mode_t mode)
-{
-#ifdef HAVE_ATTROPEN
-	/* FIXME: direct Solaris xattr syscall */
-	return attropen(path, AFPRESOURCE_EA_NETATALK, flags, mode);
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-static int ad_open_rsrc_adouble(const char *path, int flags, mode_t mode)
-{
-	char *adp = NULL;
-	int ret;
-	int fd;
-
-	ret = adouble_path(talloc_tos(), path, &adp);
-	if (ret != 0) {
-		return -1;
-	}
-
-	fd = open(adp, flags, mode);
-	TALLOC_FREE(adp);
-
-	return fd;
-}
-
-static int ad_open_rsrc(vfs_handle_struct *handle,
-			const char *path,
-			int flags,
-			mode_t mode)
+/**
+ * Read and parse resource fork, either ._ AppleDouble file or xattr
+ **/
+static ssize_t ad_header_read_rsrc(struct adouble *ad, const char *path)
 {
 	struct fruit_config_data *config = NULL;
-	int fd;
+	int fd = -1;
+	int rc = 0;
+	ssize_t len;
+	char *adpath = NULL;
+	bool opened = false;
+	int mode;
+	struct adouble *meta_ad = NULL;
+	SMB_STRUCT_STAT sbuf;
+	bool ok;
+	int saved_errno = 0;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
+	SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
 				struct fruit_config_data, return -1);
 
-	if (config->rsrc == FRUIT_RSRC_XATTR) {
-		fd = ad_open_rsrc_xattr(path, flags, mode);
-	} else {
-		fd = ad_open_rsrc_adouble(path, flags, mode);
-	}
-
-	return fd;
-}
-
-static int ad_open(vfs_handle_struct *handle,
-		   struct adouble *ad,
-		   const char *path,
-		   adouble_type_t t,
-		   int flags,
-		   mode_t mode)
-{
-	int fd;
-
-	DBG_DEBUG("Path [%s] type [%s]\n",
-		  path, t == ADOUBLE_META ? "meta" : "rsrc");
+	/* Try rw first so we can use the fd in ad_convert() */
+	mode = O_RDWR;
 
-	if (t == ADOUBLE_META) {
-		fd = ad_open_meta(path, flags, mode);
+	if (ad->ad_fsp && ad->ad_fsp->fh && (ad->ad_fsp->fh->fd != -1)) {
+		fd = ad->ad_fsp->fh->fd;
 	} else {
-		fd = ad_open_rsrc(handle, path, flags, mode);
-	}
-
-	if (fd != -1) {
-		ad->ad_opened = true;
-		ad->ad_fd = fd;
-	}
-
-	DBG_DEBUG("Path [%s] type [%s] fd [%d]\n",
-		  path, t == ADOUBLE_META ? "meta" : "rsrc", fd);
-
-	return fd;
-}
-
-static ssize_t ad_read_rsrc_xattr(struct adouble *ad,
-				  const char *path)
-{
-	int ret;
-	SMB_STRUCT_STAT st;
-
-	/* FIXME: direct sys_fstat(), don't have an fsp */
-	ret = sys_fstat(ad->ad_fd, &st,
-			lp_fake_directory_create_times(
-				SNUM(ad->ad_handle->conn)));
-	if (ret != 0) {
-		return -1;
-	}
-
-	ad_setentrylen(ad, ADEID_RFORK, st.st_ex_size);
-	return st.st_ex_size;
-}
+		if (config->rsrc == FRUIT_RSRC_XATTR) {
+			adpath = talloc_strdup(talloc_tos(), path);
+		} else {
+			rc = adouble_path(talloc_tos(), path, &adpath);
+			if (rc != 0) {
+				goto exit;
+			}
+		}
 
-static ssize_t ad_read_rsrc_adouble(struct adouble *ad,
-				    const char *path)
-{
-	struct adouble *meta_ad = NULL;
-	SMB_STRUCT_STAT sbuf;
-	char *p_ad = NULL;
-	char *p_meta_ad = NULL;
-	ssize_t len;
-	int ret;
-	bool ok;
+	retry:
+		if (config->rsrc == FRUIT_RSRC_XATTR) {
+#ifndef HAVE_ATTROPEN
+			errno = ENOSYS;
+			rc = -1;
+			goto exit;
+#else
+			/* FIXME: direct Solaris xattr syscall */
+			fd = attropen(adpath, AFPRESOURCE_EA_NETATALK,
+				      mode, 0);
+#endif
+		} else {
+			/* FIXME: direct open(), don't have an fsp */
+			fd = open(adpath, mode);
+		}
 
-	len = sys_pread(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
-	if (len != AD_DATASZ_DOT_UND) {
-		DBG_NOTICE("%s %s: bad size: %zd\n",
-			   path, strerror(errno), len);
-		return -1;
+		if (fd == -1) {
+			switch (errno) {
+			case EROFS:
+			case EACCES:
+				if (mode == O_RDWR) {
+					mode = O_RDONLY;
+					goto retry;
+				}
+				/* fall through ... */
+			default:
+				DEBUG(2, ("open AppleDouble: %s, %s\n",
+					  adpath, strerror(errno)));
+				rc = -1;
+				goto exit;
+			}
+		}
+		opened = true;
 	}
 
-	ret = sys_fstat(ad->ad_fd, &sbuf, lp_fake_directory_create_times(
+	if (config->rsrc == FRUIT_RSRC_XATTR) {
+		/* FIXME: direct sys_fstat(), don't have an fsp */
+		rc = sys_fstat(
+			fd, &sbuf,
+			lp_fake_directory_create_times(
 				SNUM(ad->ad_handle->conn)));
-	if (ret != 0) {
-		return -1;
-	}
+		if (rc != 0) {
+			goto exit;
+		}
+		len = sbuf.st_ex_size;
+		ad_setentrylen(ad, ADEID_RFORK, len);
+	} else {
+		/* FIXME: direct sys_pread(), don't have an fsp */
+		len = sys_pread(fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
+		if (len != AD_DATASZ_DOT_UND) {
+			DEBUG(2, ("%s: bad size: %zd\n",
+				  strerror(errno), len));
+			rc = -1;
+			goto exit;
+		}
 
-	/* Now parse entries */
-	ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size);
-	if (!ok) {
-		DBG_ERR("invalid AppleDouble resource %s\n", path);
-		errno = EINVAL;
-		return -1;
-	}
+		/* FIXME: direct sys_fstat(), we don't have an fsp */
+		rc = sys_fstat(fd, &sbuf,
+			       lp_fake_directory_create_times(
+				       SNUM(ad->ad_handle->conn)));
+		if (rc != 0) {
+			goto exit;
+		}
 
-	if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
-	    || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
-	    || (ad_getentryoff(ad, ADEID_RFORK)	< ADEDOFF_RFORK_DOT_UND)) {
-		DBG_ERR("invalid AppleDouble resource %s\n", path);
-		errno = EINVAL;
-		return -1;
-	}
+		/* Now parse entries */
+		ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size);
+		if (!ok) {
+			DEBUG(1, ("invalid AppleDouble ressource %s\n", path));
+			errno = EINVAL;
+			rc = -1;
+			goto exit;
+		}
 
-	if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
-		return len;
-	}
+		if ((ad_getentryoff(ad, ADEID_FINDERI)
+		     != ADEDOFF_FINDERI_DOT_UND)
+		    || (ad_getentrylen(ad, ADEID_FINDERI)
+			< ADEDLEN_FINDERI)
+		    || (ad_getentryoff(ad, ADEID_RFORK)
+			< ADEDOFF_RFORK_DOT_UND)) {
+			DEBUG(2, ("invalid AppleDouble ressource %s\n", path));
+			errno = EINVAL;
+			rc = -1;
+			goto exit;
+		}
 
-	/*
-	 * Try to fixup AppleDouble files created by OS X with xattrs
-	 * appended to the ADEID_FINDERI entry. We simply remove the
-	 * xattrs blob, this means any fancy xattr that was stored
-	 * there is lost.
-	 */
+		if ((mode == O_RDWR)
+		    && (ad_getentrylen(ad, ADEID_FINDERI) > ADEDLEN_FINDERI)) {
+			rc = ad_convert(ad, fd);
+			if (rc != 0) {
+				rc = -1;
+				goto exit;
+			}
+			/*
+			 * Can't use ad_write() because we might not have a fsp
+			 */
+			ok = ad_pack(ad);
+			if (!ok) {
+				rc = -1;
+				goto exit;
+			}
+			/* FIXME: direct sys_pwrite(), don't have an fsp */
+			len = sys_pwrite(fd, ad->ad_data,
+					 AD_DATASZ_DOT_UND, 0);
+			if (len != AD_DATASZ_DOT_UND) {
+				DEBUG(2, ("%s: bad size: %zd\n", adpath, len));
+				rc = -1;
+				goto exit;
+			}
 
-	ret = ad_convert(ad, ad->ad_fd);
-	if (ret != 0) {
-		DBG_WARNING("Failed to convert [%s]\n", path);
-		return len;
-	}
+			meta_ad = ad_init(talloc_tos(), ad->ad_handle,
+					  ADOUBLE_META, NULL);
+			if (meta_ad == NULL) {
+				rc = -1;
+				goto exit;
+			}
 
-	ok = ad_pack(ad);
-	if (!ok) {
-		DBG_WARNING("ad_pack [%s] failed\n", path);
-		return -1;
-	}
+			memcpy(ad_entry(meta_ad, ADEID_FINDERI),
+			       ad_entry(ad, ADEID_FINDERI),
+			       ADEDLEN_FINDERI);
 
-	len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
-	if (len != AD_DATASZ_DOT_UND) {
-		DBG_ERR("%s: bad size: %zd\n", path, len);
-		return -1;
+			rc = ad_write(meta_ad, path);
+			if (rc != 0) {
+				rc = -1;
+				goto exit;
+			}
+		}
 	}
 
-	meta_ad = ad_init(talloc_tos(), ad->ad_handle, ADOUBLE_META);
-	if (meta_ad == NULL) {
-		return -1;
-	}
+	DEBUG(10, ("opened AppleDouble: %s\n", path));
 
-	p_ad = ad_get_entry(ad, ADEID_FINDERI);
-	if (p_ad == NULL) {
-		TALLOC_FREE(meta_ad);
-		return -1;
+exit:
+	if (rc != 0) {
+		saved_errno = errno;
+		len = -1;
 	}
-	p_meta_ad = ad_get_entry(meta_ad, ADEID_FINDERI);
-	if (p_meta_ad == NULL) {
-		TALLOC_FREE(meta_ad);
-		return -1;
+	if (opened && fd != -1) {
+		close(fd);
 	}
-
-	memcpy(p_meta_ad, p_ad, ADEDLEN_FINDERI);
-
-	ret = ad_set(meta_ad, path);
+	TALLOC_FREE(adpath);
 	TALLOC_FREE(meta_ad);
-	if (ret != 0) {
-		return -1;
-	}
-
-	return len;
-}
-
-/**
- * Read and parse resource fork, either ._ AppleDouble file or xattr
- **/
-static ssize_t ad_read_rsrc(struct adouble *ad,
-			    const char *path)
-{
-	struct fruit_config_data *config = NULL;
-	ssize_t len;
-
-	SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config,
-				struct fruit_config_data, return -1);
-
-	if (config->rsrc == FRUIT_RSRC_XATTR) {
-		len = ad_read_rsrc_xattr(ad, path);
-	} else {
-		len = ad_read_rsrc_adouble(ad, path);
+	if (rc != 0) {
+		errno = saved_errno;
 	}
-
 	return len;
 }
 
@@ -1077,23 +1012,14 @@ static ssize_t ad_read(struct adouble *ad, const char *path)
 {
 	switch (ad->ad_type) {
 	case ADOUBLE_META:
-		return ad_read_meta(ad, path);
+		return ad_header_read_meta(ad, path);
 	case ADOUBLE_RSRC:
-		return ad_read_rsrc(ad, path);
+		return ad_header_read_rsrc(ad, path);
 	default:
 		return -1;
 	}
 }
 
-static int adouble_destructor(struct adouble *ad)
-{
-	if ((ad->ad_fd != -1) && ad->ad_opened) {
-		close(ad->ad_fd);
-		ad->ad_fd = -1;
-	}
-	return 0;
-}
-
 /**
  * Allocate a struct adouble without initialiing it
  *
@@ -1103,11 +1029,14 @@ static int adouble_destructor(struct adouble *ad)
  * @param[in] ctx        talloc context
  * @param[in] handle     vfs handle
  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
+
+ * @param[in] fsp        if not NULL (for stream IO), the adouble handle is
+ *                       added as an fsp extension
  *
  * @return               adouble handle
  **/
 static struct adouble *ad_alloc(TALLOC_CTX *ctx, vfs_handle_struct *handle,
-				adouble_type_t type)
+				adouble_type_t type, files_struct *fsp)
 {
 	int rc = 0;
 	size_t adsize = 0;
@@ -1130,27 +1059,39 @@ static struct adouble *ad_alloc(TALLOC_CTX *ctx, vfs_handle_struct *handle,
 		return NULL;
 	}
 
-	ad = talloc_zero(ctx, struct adouble);
-	if (ad == NULL) {
-		rc = -1;
-		goto exit;
-	}
-
-	if (adsize) {
-		ad->ad_data = talloc_zero_array(ad, char, adsize);
-		if (ad->ad_data == NULL) {
+	if (!fsp) {
+		ad = talloc_zero(ctx, struct adouble);
+		if (ad == NULL) {
+			rc = -1;
+			goto exit;
+		}
+		if (adsize) {
+			ad->ad_data = talloc_zero_array(ad, char, adsize);
+		}
+	} else {
+		ad = (struct adouble *)VFS_ADD_FSP_EXTENSION(handle, fsp,
+							     struct adouble,
+							     NULL);
+		if (ad == NULL) {
 			rc = -1;
 			goto exit;
 		}
+		if (adsize) {
+			ad->ad_data = talloc_zero_array(
+				VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+				char, adsize);
+		}
+		ad->ad_fsp = fsp;
 	}
 
+	if (adsize && ad->ad_data == NULL) {
+		rc = -1;
+		goto exit;
+	}
 	ad->ad_handle = handle;
 	ad->ad_type = type;
 	ad->ad_magic = AD_MAGIC;
 	ad->ad_version = AD_VERSION;
-	ad->ad_fd = -1;
-
-	talloc_set_destructor(ad, adouble_destructor);
 
 exit:
 	if (rc != 0) {
@@ -1165,11 +1106,12 @@ exit:
  * @param[in] ctx        talloc context
  * @param[in] handle     vfs handle
  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
+ * @param[in] fsp        file handle, may be NULL for a type of e_ad_meta
  *
  * @return               adouble handle, initialized
  **/
 static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle,
-			       adouble_type_t type)
+			       adouble_type_t type, files_struct *fsp)
 {
 	int rc = 0;
 	const struct ad_entry_order  *eid;
@@ -1195,7 +1137,7 @@ static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle,
 		return NULL;
 	}
 
-	ad = ad_alloc(ctx, handle, type);
+	ad = ad_alloc(ctx, handle, type, fsp);
 	if (ad == NULL) {
 		return NULL;
 	}
@@ -1234,42 +1176,16 @@ static struct adouble *ad_get(TALLOC_CTX *ctx, vfs_handle_struct *handle,
 	int rc = 0;
 	ssize_t len;
 	struct adouble *ad = NULL;
-	int fd;
-	int mode;
 
 	DEBUG(10, ("ad_get(%s) called for %s\n",
 		   type == ADOUBLE_META ? "meta" : "rsrc", path));
 
-	ad = ad_alloc(ctx, handle, type);
+	ad = ad_alloc(ctx, handle, type, NULL);
 	if (ad == NULL) {
 		rc = -1;
 		goto exit;
 	}
 
-	/*
-	 * Here's the deal: for ADOUBLE_META we can do without an fd
-	 * as we can issue path based xattr calls. For ADOUBLE_RSRC
-	 * however we need a full-fledged fd for file IO on the ._
-	 * file.
-	 */
-	if (type == ADOUBLE_RSRC) {
-		/* Try rw first so we can use the fd in ad_convert() */
-		mode = O_RDWR;
-
-		fd = ad_open(handle, ad, path, ADOUBLE_RSRC, mode, 0);
-		if (fd == -1 && ((errno == EROFS) || (errno == EACCES))) {
-			mode = O_RDONLY;
-			fd = ad_open(handle, ad, path, ADOUBLE_RSRC, mode, 0);
-		}
-
-		if (fd == -1) {
-			DBG_DEBUG("ad_open [%s] error [%s]\n",
-				  path, strerror(errno));
-			rc = -1;
-			goto exit;
-		}
-	}
-
 	len = ad_read(ad, path);
 	if (len == -1) {
 		DEBUG(10, ("error reading AppleDouble for %s\n", path));
@@ -1288,175 +1204,53 @@ exit:
 }
 
 /**
- * Return AppleDouble data for a file
+ * Set AppleDouble metadata on a file or directory
  *
- * @param[in] ctx      talloc context
- * @param[in] handle   vfs handle
- * @param[in] fsp      fsp to use for IO
- * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
+ * @param[in] ad      adouble handle
+
+ * @param[in] path    pathname to file or directory, may be NULL for a
+ *                    resource fork
  *
- * @return             talloced struct adouble or NULL on error
+ * @return            status code, 0 means success
  **/
-static struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
-			       files_struct *fsp, adouble_type_t type)
+static int ad_write(struct adouble *ad, const char *path)
 {
 	int rc = 0;
 	ssize_t len;
-	struct adouble *ad = NULL;
-	char *path = fsp->base_fsp->fsp_name->base_name;
-
-	DBG_DEBUG("ad_get(%s) path [%s]\n",
-		  type == ADOUBLE_META ? "meta" : "rsrc",
-		  fsp_str_dbg(fsp));
+	bool ok;
 
-	ad = ad_alloc(ctx, handle, type);
-	if (ad == NULL) {
-		rc = -1;
-		goto exit;
+	ok = ad_pack(ad);
+	if (!ok) {
+		return -1;
 	}
 
-	if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) {
-		ad->ad_fd = fsp->fh->fd;
-	} else {
-		/*
-		 * Here's the deal: for ADOUBLE_META we can do without an fd
-		 * as we can issue path based xattr calls. For ADOUBLE_RSRC
-		 * however we need a full-fledged fd for file IO on the ._
-		 * file.
-		 */
-		int fd;
-		int mode;
-
-		if (type == ADOUBLE_RSRC) {
-			/* Try rw first so we can use the fd in ad_convert() */
-			mode = O_RDWR;
-
-			fd = ad_open(handle, ad, path, ADOUBLE_RSRC, mode, 0);
-			if (fd == -1 &&
-			    ((errno == EROFS) || (errno == EACCES)))
-			{
-				mode = O_RDONLY;
-				fd = ad_open(handle, ad, path, ADOUBLE_RSRC,
-					     mode, 0);
-			}
-
-			if (fd == -1) {
-				DBG_DEBUG("error opening AppleDouble for %s\n", path);
-				rc = -1;
-				goto exit;
-			}
+	switch (ad->ad_type) {
+	case ADOUBLE_META:
+		rc = SMB_VFS_SETXATTR(ad->ad_handle->conn, path,
+				      AFPINFO_EA_NETATALK, ad->ad_data,
+				      AD_DATASZ_XATTR, 0);
+		break;
+	case ADOUBLE_RSRC:
+		if ((ad->ad_fsp == NULL)
+		    || (ad->ad_fsp->fh == NULL)
+		    || (ad->ad_fsp->fh->fd == -1)) {
+			rc = -1;
+			goto exit;
 		}
+		/* FIXME: direct sys_pwrite(), don't have an fsp */
+		len = sys_pwrite(ad->ad_fsp->fh->fd, ad->ad_data,
+				 talloc_get_size(ad->ad_data), 0);
+		if (len != talloc_get_size(ad->ad_data)) {
+			DEBUG(1, ("short write on %s: %zd",
+				  fsp_str_dbg(ad->ad_fsp), len));
+			rc = -1;
+			goto exit;
+		}
+		break;
+	default:
+		return -1;
 	}
-
-	len = ad_read(ad, path);
-	if (len == -1) {
-		DBG_DEBUG("error reading AppleDouble for %s\n", path);
-		rc = -1;
-		goto exit;
-	}
-
 exit:
-	DBG_DEBUG("ad_get(%s) path [%s] rc [%d]\n",
-		  type == ADOUBLE_META ? "meta" : "rsrc",
-		  fsp_str_dbg(fsp), rc);
-
-	if (rc != 0) {
-		TALLOC_FREE(ad);
-	}
-	return ad;
-}
-
-/**
- * Set AppleDouble metadata on a file or directory
- *
- * @param[in] ad      adouble handle
- *
- * @param[in] path    pathname to file or directory
- *
- * @return            status code, 0 means success
- **/
-static int ad_set(struct adouble *ad, const char *path)
-{
-	bool ok;
-	int ret;
-
-	DBG_DEBUG("Path [%s]\n", path);
-
-	if (ad->ad_type != ADOUBLE_META) {
-		DBG_ERR("ad_set on [%s] used with ADOUBLE_RSRC\n", path);
-		return -1;
-	}
-
-	ok = ad_pack(ad);
-	if (!ok) {
-		return -1;
-	}
-
-	ret = SMB_VFS_SETXATTR(ad->ad_handle->conn,
-			       path,
-			       AFPINFO_EA_NETATALK,
-			       ad->ad_data,
-			       AD_DATASZ_XATTR, 0);
-
-	DBG_DEBUG("Path [%s] ret [%d]\n", path, ret);
-
-	return ret;
-}
-
-/**
- * Set AppleDouble metadata on a file or directory
- *
- * @param[in] ad      adouble handle
- * @param[in] fsp     file handle
- *
- * @return            status code, 0 means success
- **/
-static int ad_fset(struct adouble *ad, files_struct *fsp)
-{
-	int rc = -1;
-	ssize_t len;
-	bool ok;
-
-	DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
-
-	if ((fsp == NULL)
-	    || (fsp->fh == NULL)
-	    || (fsp->fh->fd == -1))
-	{
-		smb_panic("bad fsp");
-	}
-
-	ok = ad_pack(ad);
-	if (!ok) {
-		return -1;
-	}
-
-	switch (ad->ad_type) {
-	case ADOUBLE_META:
-		rc = SMB_VFS_FSETXATTR(fsp, AFPINFO_EA_NETATALK,
-				       ad->ad_data,
-				       AD_DATASZ_XATTR, 0);
-		break;
-
-	case ADOUBLE_RSRC:
-		len = SMB_VFS_NEXT_PWRITE(ad->ad_handle,
-					  fsp,
-					  ad->ad_data,
-					  talloc_get_size(ad->ad_data),
-					  0);
-		if (len != (ssize_t)talloc_get_size(ad->ad_data)) {
-			DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
-			return -1;
-		}
-		rc = 0;
-		break;
-
-	default:
-		return -1;
-	}
-
-	DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
-
 	return rc;
 }
 
@@ -1697,6 +1491,19 @@ static SMB_INO_T fruit_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
 	return result;
 }
 
+/**
+ * Ensure ad_fsp is still valid
+ **/
+static bool fruit_fsp_recheck(struct adouble *ad, files_struct *fsp)
+{
+	if (ad->ad_fsp == fsp) {
+		return true;
+	}
+	ad->ad_fsp = fsp;
+
+	return true;
+}
+
 static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
 			     struct stream_struct **streams,
 			     const char *name, off_t size,
@@ -1723,40 +1530,6 @@ static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
 	return true;
 }
 
-static bool filter_empty_rsrc_stream(unsigned int *num_streams,
-				     struct stream_struct **streams)
-{
-	struct stream_struct *tmp = *streams;
-	unsigned int i;
-
-	if (*num_streams == 0) {
-		return true;
-	}
-
-	for (i = 0; i < *num_streams; i++) {
-		if (strequal_m(tmp[i].name, AFPRESOURCE_STREAM)) {
-			break;
-		}
-	}
-
-	if (i == *num_streams) {
-		return true;
-	}
-
-	if (tmp[i].size > 0) {
-		return true;
-	}
-
-	TALLOC_FREE(tmp[i].name);
-	if (*num_streams - 1 > i) {
-		memmove(&tmp[i], &tmp[i+1],
-			(*num_streams - i - 1) * sizeof(struct stream_struct));
-	}
-
-	*num_streams -= 1;
-	return true;
-}
-
 static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
 			     struct stream_struct **streams,
 			     const char *name)
@@ -1788,29 +1561,16 @@ static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
 	return true;
 }
 
-static bool ad_empty_finderinfo(const struct adouble *ad)
+static bool empty_finderinfo(const struct adouble *ad)
 {
-	int cmp;
-	char emptybuf[ADEDLEN_FINDERI] = {0};
-	char *fi = NULL;
-
-	fi = ad_get_entry(ad, ADEID_FINDERI);
-	if (fi == NULL) {
-		DBG_ERR("Missing FinderInfo in struct adouble [%p]\n", ad);
-		return false;
-	}
 
-	cmp = memcmp(emptybuf, fi, ADEDLEN_FINDERI);
-	return (cmp == 0);
-}
-
-static bool ai_empty_finderinfo(const AfpInfo *ai)
-{
-	int cmp;
 	char emptybuf[ADEDLEN_FINDERI] = {0};
-
-	cmp = memcmp(emptybuf, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
-	return (cmp == 0);
+	if (memcmp(emptybuf,
+		   ad_entry(ad, ADEID_FINDERI),
+		   ADEDLEN_FINDERI) == 0) {
+		return true;
+	}
+	return false;
 }
 
 /**
@@ -1822,21 +1582,6 @@ static void update_btime(vfs_handle_struct *handle,
 	uint32_t t;
 	struct timespec creation_time = {0};
 	struct adouble *ad;
-	struct fruit_config_data *config = NULL;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
-				return);
-
-	switch (config->meta) {
-	case FRUIT_META_STREAM:
-		return;
-	case FRUIT_META_NETATALK:
-		/* Handled below */
-		break;
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", config->meta);
-		return;
-	}
 
 	ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META);
 	if (ad == NULL) {
@@ -1952,8 +1697,6 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 	struct byte_range_lock *br_lck = NULL;
 	bool open_for_reading, open_for_writing, deny_read, deny_write;
 	off_t off;
-	bool have_read = false;
-	int flags;
 
 	/* FIXME: hardcoded data fork, add resource fork */
 	enum apple_fork fork_type = APPLE_FORK_DATA;
@@ -1965,26 +1708,6 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 		  deny_mode & DENY_READ ? "DENY_READ" : "-",
 		  deny_mode & DENY_WRITE ? "DENY_WRITE" : "-"));
 
-	if (fsp->fh->fd == -1) {
-		return NT_STATUS_OK;
-	}
-
-	flags = fcntl(fsp->fh->fd, F_GETFL);
-	if (flags == -1) {
-		DBG_ERR("fcntl get flags [%s] fd [%d] failed [%s]\n",
-			fsp_str_dbg(fsp), fsp->fh->fd, strerror(errno));
-		return map_nt_error_from_unix(errno);
-	}
-
-	if (flags & (O_RDONLY|O_RDWR)) {
-		/*
-		 * Applying fcntl read locks requires an fd opened for
-		 * reading. This means we won't be applying locks for
-		 * files openend write-only, but what can we do...
-		 */
-		have_read = true;
-	}
-
 	/*
 	 * Check read access and deny read mode
 	 */
@@ -2006,7 +1729,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 		}
 
 		/* Set locks */
-		if ((access_mask & FILE_READ_DATA) && have_read) {
+		if (access_mask & FILE_READ_DATA) {
 			off = access_to_netatalk_brl(fork_type, FILE_READ_DATA);
 			br_lck = do_lock(
 				handle->conn->sconn->msg_ctx, fsp,
@@ -2020,7 +1743,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 			TALLOC_FREE(br_lck);
 		}
 
-		if ((deny_mode & DENY_READ) && have_read) {
+		if (deny_mode & DENY_READ) {
 			off = denymode_to_netatalk_brl(fork_type, DENY_READ);
 			br_lck = do_lock(
 				handle->conn->sconn->msg_ctx, fsp,
@@ -2056,7 +1779,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 		}
 
 		/* Set locks */
-		if ((access_mask & FILE_WRITE_DATA) && have_read) {
+		if (access_mask & FILE_WRITE_DATA) {
 			off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA);
 			br_lck = do_lock(
 				handle->conn->sconn->msg_ctx, fsp,
@@ -2070,7 +1793,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle,
 			TALLOC_FREE(br_lck);
 
 		}
-		if ((deny_mode & DENY_WRITE) && have_read) {
+		if (deny_mode & DENY_WRITE) {
 			off = denymode_to_netatalk_brl(fork_type, DENY_WRITE);
 			br_lck = do_lock(
 				handle->conn->sconn->msg_ctx, fsp,
@@ -2217,344 +1940,135 @@ static NTSTATUS check_aapl(vfs_handle_struct *handle,
 	return status;
 }
 
-static bool readdir_attr_meta_finderi_stream(
-	struct vfs_handle_struct *handle,
-	const struct smb_filename *smb_fname,
-	AfpInfo *ai)
+static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle,
+				     const struct smb_filename *smb_fname,
+				     struct readdir_attr_data *attr_data)
 {
-	struct smb_filename *stream_name = NULL;
-	files_struct *fsp = NULL;
-	ssize_t nread;
-	NTSTATUS status;
-	int ret;
-	bool ok;
-	uint8_t buf[AFP_INFO_SIZE];
+	NTSTATUS status = NT_STATUS_OK;
+	uint32_t date_added;
+	struct adouble *ad = NULL;
+	struct fruit_config_data *config = NULL;
 
-	stream_name = synthetic_smb_fname(talloc_tos(),
-					  smb_fname->base_name,
-					  AFPINFO_STREAM_NAME,
-					  NULL, smb_fname->flags);
-	if (stream_name == NULL) {
-		return false;
-	}
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data,
+				return NT_STATUS_UNSUCCESSFUL);
 
-	ret = SMB_VFS_STAT(handle->conn, stream_name);
-	if (ret != 0) {
-		return false;
-	}
 
-	status = SMB_VFS_CREATE_FILE(
-		handle->conn,                           /* conn */
-		NULL,                                   /* req */
-		0,                                      /* root_dir_fid */
-		stream_name,				/* fname */
-		FILE_READ_DATA,                         /* access_mask */
-		(FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
-			FILE_SHARE_DELETE),
-		FILE_OPEN,                              /* create_disposition*/
-		0,                                      /* create_options */
-		0,                                      /* file_attributes */
-		INTERNAL_OPEN_ONLY,                     /* oplock_request */
-		NULL,					/* lease */
-                0,                                      /* allocation_size */
-		0,                                      /* private_flags */
-		NULL,                                   /* sd */
-		NULL,                                   /* ea_list */
-		&fsp,                                   /* result */
-		NULL,                                   /* pinfo */
-		NULL, NULL);				/* create context */
-
-	TALLOC_FREE(stream_name);
+	/* Ensure we return a default value in the creation_date field */
+	RSIVAL(&attr_data->attr_data.aapl.finder_info, 12, AD_DATE_START);
 
-	if (!NT_STATUS_IS_OK(status)) {
-		return false;
-	}
+	/*
+	 * Resource fork length
+	 */
 
-	nread = SMB_VFS_PREAD(fsp, &buf[0], AFP_INFO_SIZE, 0);
-	if (nread != AFP_INFO_SIZE) {
-		DBG_ERR("short read [%s] [%zd/%d]\n",
-			smb_fname_str_dbg(stream_name), nread, AFP_INFO_SIZE);
-		ok = false;
-		goto fail;
+	if (config->readdir_attr_rsize) {
+		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
+			    ADOUBLE_RSRC);
+		if (ad) {
+			attr_data->attr_data.aapl.rfork_size = ad_getentrylen(
+				ad, ADEID_RFORK);
+			TALLOC_FREE(ad);
+		}
 	}
 
-	memcpy(&ai->afpi_FinderInfo[0], &buf[AFP_OFF_FinderInfo],
-	       AFP_FinderSize);
-
-	ok = true;
+	/*
+	 * FinderInfo
+	 */
 
-fail:
-	if (fsp != NULL) {
-		close_file(NULL, fsp, NORMAL_CLOSE);
-	}
+	if (config->readdir_attr_finder_info) {
+		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
+			    ADOUBLE_META);
+		if (ad) {
+			if (S_ISREG(smb_fname->st.st_ex_mode)) {
+				/* finder_type */
+				memcpy(&attr_data->attr_data.aapl.finder_info[0],
+				       ad_entry(ad, ADEID_FINDERI), 4);
+
+				/* finder_creator */
+				memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4,
+				       ad_entry(ad, ADEID_FINDERI) + 4, 4);
+			}
 
-	return ok;
-}
+			/* finder_flags */
+			memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8,
+			       ad_entry(ad, ADEID_FINDERI) + 8, 2);
 
-static bool readdir_attr_meta_finderi_netatalk(
-	struct vfs_handle_struct *handle,
-	const struct smb_filename *smb_fname,
-	AfpInfo *ai)
-{
-	struct adouble *ad = NULL;
-	char *p = NULL;
+			/* finder_ext_flags */
+			memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10,
+			       ad_entry(ad, ADEID_FINDERI) + 24, 2);
 
-	ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META);
-	if (ad == NULL) {
-		return false;
-	}
+			/* creation date */
+			date_added = convert_time_t_to_uint32_t(
+				smb_fname->st.st_ex_btime.tv_sec - AD_DATE_DELTA);
+			RSIVAL(&attr_data->attr_data.aapl.finder_info[0], 12, date_added);
 
-	p = ad_get_entry(ad, ADEID_FINDERI);
-	if (p == NULL) {
-		DBG_ERR("No ADEID_FINDERI for [%s]\n", smb_fname->base_name);
-		TALLOC_FREE(ad);
-		return false;
+			TALLOC_FREE(ad);
+		}
 	}
 
-	memcpy(&ai->afpi_FinderInfo[0], p, AFP_FinderSize);
 	TALLOC_FREE(ad);
-	return true;
+	return status;
 }
 
-static bool readdir_attr_meta_finderi(struct vfs_handle_struct *handle,
-				      const struct smb_filename *smb_fname,
-				      struct readdir_attr_data *attr_data)
+/* Search MS NFS style ACE with UNIX mode */
+static NTSTATUS check_ms_nfs(vfs_handle_struct *handle,
+			     files_struct *fsp,
+			     const struct security_descriptor *psd,
+			     mode_t *pmode,
+			     bool *pdo_chmod)
 {
+	uint32_t i;
 	struct fruit_config_data *config = NULL;
-	uint32_t date_added;
-	AfpInfo ai = {0};
-	bool ok;
+
+	*pdo_chmod = false;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data,
-				return false);
-
-	switch (config->meta) {
-	case FRUIT_META_NETATALK:
-		ok = readdir_attr_meta_finderi_netatalk(
-			handle, smb_fname, &ai);
-		break;
-
-	case FRUIT_META_STREAM:
-		ok = readdir_attr_meta_finderi_stream(
-			handle, smb_fname, &ai);
-		break;
-
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", config->meta);
-		return false;
-	}
+				return NT_STATUS_UNSUCCESSFUL);
 
-	if (!ok) {
-		/* Don't bother with errors, it's likely ENOENT */
-		return true;
+	if (psd->dacl == NULL || !config->unix_info_enabled) {
+		return NT_STATUS_OK;
 	}
 
-	if (S_ISREG(smb_fname->st.st_ex_mode)) {
-		/* finder_type */
-		memcpy(&attr_data->attr_data.aapl.finder_info[0],
-		       &ai.afpi_FinderInfo[0], 4);
+	for (i = 0; i < psd->dacl->num_aces; i++) {
+		if (dom_sid_compare_domain(
+			    &global_sid_Unix_NFS_Mode,
+			    &psd->dacl->aces[i].trustee) == 0) {
+			*pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
+			*pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+			*pdo_chmod = true;
 
-		/* finder_creator */
-		memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4,
-		       &ai.afpi_FinderInfo[4], 4);
+			DEBUG(10, ("MS NFS chmod request %s, %04o\n",
+				   fsp_str_dbg(fsp), (unsigned)(*pmode)));
+			break;
+		}
 	}
 
-	/* finder_flags */
-	memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8,
-	       &ai.afpi_FinderInfo[8], 2);
-
-	/* finder_ext_flags */
-	memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10,
-	       &ai.afpi_FinderInfo[24], 2);
+	return NT_STATUS_OK;
+}
 
-	/* creation date */
-	date_added = convert_time_t_to_uint32_t(
-		smb_fname->st.st_ex_btime.tv_sec - AD_DATE_DELTA);
+/****************************************************************************
+ * VFS ops
+ ****************************************************************************/
 
-	RSIVAL(&attr_data->attr_data.aapl.finder_info[0], 12, date_added);
+static int fruit_connect(vfs_handle_struct *handle,
+			 const char *service,
+			 const char *user)
+{
+	int rc;
+	char *list = NULL, *newlist = NULL;
+	struct fruit_config_data *config;
 
-	return true;
-}
+	DEBUG(10, ("fruit_connect\n"));
 
-static uint64_t readdir_attr_rfork_size_adouble(
-	struct vfs_handle_struct *handle,
-	const struct smb_filename *smb_fname)
-{
-	struct adouble *ad = NULL;
-	uint64_t rfork_size;
+	rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
+	if (rc < 0) {
+		return rc;
+	}
 
-	ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
-		    ADOUBLE_RSRC);
-	if (ad == NULL) {
-		return 0;
-	}
-
-	rfork_size = ad_getentrylen(ad, ADEID_RFORK);
-	TALLOC_FREE(ad);
-
-	return rfork_size;
-}
-
-static uint64_t readdir_attr_rfork_size_stream(
-	struct vfs_handle_struct *handle,
-	const struct smb_filename *smb_fname)
-{
-	struct smb_filename *stream_name = NULL;
-	int ret;
-	uint64_t rfork_size;
-
-	stream_name = synthetic_smb_fname(talloc_tos(),
-					  smb_fname->base_name,
-					  AFPRESOURCE_STREAM_NAME,
-					  NULL, 0);
-	if (stream_name == NULL) {
-		return 0;
-	}
-
-	ret = SMB_VFS_STAT(handle->conn, stream_name);
-	if (ret != 0) {
-		TALLOC_FREE(stream_name);
-		return 0;
-	}
-
-	rfork_size = stream_name->st.st_ex_size;
-	TALLOC_FREE(stream_name);
-
-	return rfork_size;
-}
-
-static uint64_t readdir_attr_rfork_size(struct vfs_handle_struct *handle,
-					const struct smb_filename *smb_fname)
-{
-	struct fruit_config_data *config = NULL;
-	uint64_t rfork_size;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data,
-				return 0);
-
-	switch (config->rsrc) {
-	case FRUIT_RSRC_ADFILE:
-	case FRUIT_RSRC_XATTR:
-		rfork_size = readdir_attr_rfork_size_adouble(handle,
-							     smb_fname);
-		break;
-
-	case FRUIT_META_STREAM:
-		rfork_size = readdir_attr_rfork_size_stream(handle,
-							    smb_fname);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
-		rfork_size = 0;
-		break;
-	}
-
-	return rfork_size;
-}
-
-static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle,
-				     const struct smb_filename *smb_fname,
-				     struct readdir_attr_data *attr_data)
-{
-	NTSTATUS status = NT_STATUS_OK;
-	struct fruit_config_data *config = NULL;
-	bool ok;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data,
-				return NT_STATUS_UNSUCCESSFUL);
-
-
-	/* Ensure we return a default value in the creation_date field */
-	RSIVAL(&attr_data->attr_data.aapl.finder_info, 12, AD_DATE_START);
-
-	/*
-	 * Resource fork length
-	 */
-
-	if (config->readdir_attr_rsize) {
-		uint64_t rfork_size;
-
-		rfork_size = readdir_attr_rfork_size(handle, smb_fname);
-		attr_data->attr_data.aapl.rfork_size = rfork_size;
-	}
-
-	/*
-	 * FinderInfo
-	 */
-
-	if (config->readdir_attr_finder_info) {
-		ok = readdir_attr_meta_finderi(handle, smb_fname, attr_data);
-		if (!ok) {
-			status = NT_STATUS_INTERNAL_ERROR;
-		}
-	}
-
-	return status;
-}
-
-/* Search MS NFS style ACE with UNIX mode */
-static NTSTATUS check_ms_nfs(vfs_handle_struct *handle,
-			     files_struct *fsp,
-			     const struct security_descriptor *psd,
-			     mode_t *pmode,
-			     bool *pdo_chmod)
-{
-	uint32_t i;
-	struct fruit_config_data *config = NULL;
-
-	*pdo_chmod = false;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data,
-				return NT_STATUS_UNSUCCESSFUL);
-
-	if (psd->dacl == NULL || !config->unix_info_enabled) {
-		return NT_STATUS_OK;
-	}
-
-	for (i = 0; i < psd->dacl->num_aces; i++) {
-		if (dom_sid_compare_domain(
-			    &global_sid_Unix_NFS_Mode,
-			    &psd->dacl->aces[i].trustee) == 0) {
-			*pmode = (mode_t)psd->dacl->aces[i].trustee.sub_auths[2];
-			*pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
-			*pdo_chmod = true;
-
-			DEBUG(10, ("MS NFS chmod request %s, %04o\n",
-				   fsp_str_dbg(fsp), (unsigned)(*pmode)));
-			break;
-		}
-	}
-
-	return NT_STATUS_OK;
-}
-
-/****************************************************************************
- * VFS ops
- ****************************************************************************/
-
-static int fruit_connect(vfs_handle_struct *handle,
-			 const char *service,
-			 const char *user)
-{
-	int rc;
-	char *list = NULL, *newlist = NULL;
-	struct fruit_config_data *config;
-
-	DEBUG(10, ("fruit_connect\n"));
-
-	rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
-	if (rc < 0) {
-		return rc;
-	}
-
-	rc = init_fruit_config(handle);
-	if (rc != 0) {
-		return rc;
+	rc = init_fruit_config(handle);
+	if (rc != 0) {
+		return rc;
 	}
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -2602,87 +2116,25 @@ static int fruit_connect(vfs_handle_struct *handle,
 	return rc;
 }
 
-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;
-
-	hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-	if (hostfd == -1) {
-		return -1;
-	}
-
-	if (!(flags & (O_CREAT | O_TRUNC))) {
-		return hostfd;
-	}
-
-	ai = afpinfo_new(talloc_tos());
-	if (ai == NULL) {
-		rc = -1;
-		goto fail;
-	}
-
-	len = afpinfo_pack(ai, afpinfo_buf);
-	if (len != AFP_INFO_SIZE) {
-		rc = -1;
-		goto fail;
-	}
-
-	/* 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);
-	if (written != AFP_INFO_SIZE) {
-		DBG_ERR("bad write [%zd/%d]\n", written, AFP_INFO_SIZE);
-		rc = -1;
-		goto fail;
-	}
-
-	/* Reset fd, set above just for SMB_VFS_NEXT_PWRITE() */
-	fsp->fh->fd = -1;
-
-	rc = 0;
-fail:
-	DBG_DEBUG("rc=%d, fd=%d\n", rc, hostfd);
-
-	if (rc != 0) {
-		int saved_errno = errno;
-		if (hostfd >= 0) {
-			/*
-			 * BUGBUGBUG -- we would need to call
-			 * fd_close_posix here, but we don't have a
-			 * full fsp yet
-			 */
-			fsp->fh->fd = hostfd;
-			SMB_VFS_CLOSE(fsp);
-		}
-		hostfd = -1;
-		errno = saved_errno;
-	}
-	return hostfd;
-}
-
-static int fruit_open_meta_netatalk(vfs_handle_struct *handle,
-				    struct smb_filename *smb_fname,
-				    files_struct *fsp,
-				    int flags,
-				    mode_t mode)
+static int fruit_open_meta(vfs_handle_struct *handle,
+			   struct smb_filename *smb_fname,
+			   files_struct *fsp, int flags, mode_t mode)
 {
 	int rc = 0;
+	struct fruit_config_data *config = NULL;
 	struct smb_filename *smb_fname_base = NULL;
 	int baseflags;
 	int hostfd = -1;
 	struct adouble *ad = NULL;
 
-	DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
+	DEBUG(10, ("fruit_open_meta for %s\n", smb_fname_str_dbg(smb_fname)));
+
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
+
+	if (config->meta == FRUIT_META_STREAM) {
+		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+	}
 
 	/* Create an smb_filename with stream_name == NULL. */
 	smb_fname_base = synthetic_smb_fname(talloc_tos(),
@@ -2732,22 +2184,29 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle,
 		 * The attribute does not exist or needs to be truncated,
 		 * create an AppleDouble EA
 		 */
-		ad = ad_init(fsp, handle, ADOUBLE_META);
+		ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+			     handle, ADOUBLE_META, fsp);
 		if (ad == NULL) {
 			rc = -1;
 			goto exit;
 		}
 
-		fsp->fh->fd = hostfd;
-
-		rc = ad_fset(ad, fsp);
-		fsp->fh->fd = -1;
+		rc = ad_write(ad, smb_fname->base_name);
 		if (rc != 0) {
 			rc = -1;
 			goto exit;
 		}
-
-		TALLOC_FREE(ad);
+	} else {
+		ad = ad_alloc(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+			      handle, ADOUBLE_META, fsp);
+		if (ad == NULL) {
+			rc = -1;
+			goto exit;
+		}
+		if (ad_read(ad, smb_fname->base_name) == -1) {
+			rc = -1;
+			goto exit;
+		}
 	}
 
 exit:
@@ -2769,64 +2228,47 @@ exit:
 	return hostfd;
 }
 
-static int fruit_open_meta(vfs_handle_struct *handle,
+static int fruit_open_rsrc(vfs_handle_struct *handle,
 			   struct smb_filename *smb_fname,
 			   files_struct *fsp, int flags, mode_t mode)
 {
-	int fd;
-	struct fruit_config_data *config = NULL;
-	struct fio *fio = NULL;
-
-	DBG_DEBUG("path [%s]\n", smb_fname_str_dbg(smb_fname));
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
-
-	switch (config->meta) {
-	case FRUIT_META_STREAM:
-		fd = fruit_open_meta_stream(handle, smb_fname,
-					    fsp, flags, mode);
-		break;
-
-	case FRUIT_META_NETATALK:
-		fd = fruit_open_meta_netatalk(handle, smb_fname,
-					      fsp, flags, mode);
-		break;
-
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", config->meta);
-		return -1;
-	}
-
-	DBG_DEBUG("path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
-
-	if (fd == -1) {
-		return -1;
-	}
-
-	fio = (struct fio *)VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
-	fio->type = ADOUBLE_META;
-	fio->config = config;
-
-	return fd;
-}
-
-static int fruit_open_rsrc_adouble(vfs_handle_struct *handle,
-				   struct smb_filename *smb_fname,
-				   files_struct *fsp,
-				   int flags,
-				   mode_t mode)
-{
 	int rc = 0;
+	struct fruit_config_data *config = NULL;
 	struct adouble *ad = NULL;
 	struct smb_filename *smb_fname_base = NULL;
-	struct fruit_config_data *config = NULL;
 	char *adpath = NULL;
 	int hostfd = -1;
 
+	DEBUG(10, ("fruit_open_rsrc for %s\n", smb_fname_str_dbg(smb_fname)));
+
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data, return -1);
 
+	switch (config->rsrc) {
+	case FRUIT_RSRC_STREAM:
+		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+	case FRUIT_RSRC_XATTR:
+#ifdef HAVE_ATTROPEN
+		hostfd = attropen(smb_fname->base_name,
+				  AFPRESOURCE_EA_NETATALK, flags, mode);
+		if (hostfd == -1) {
+			return -1;
+		}
+		ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+			     handle, ADOUBLE_RSRC, fsp);
+		if (ad == NULL) {
+			rc = -1;
+			goto exit;
+		}
+		goto exit;
+#else
+		errno = ENOTSUP;
+		return -1;
+#endif
+	default:
+		break;
+	}
+
 	if (!(flags & O_CREAT) && !VALID_STAT(smb_fname->st)) {
 		rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
 		if (rc != 0) {
@@ -2872,28 +2314,38 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle,
 		goto exit;
 	}
 
+	/* REVIEW: we need this in ad_write() */
+	fsp->fh->fd = hostfd;
+
 	if (flags & (O_CREAT | O_TRUNC)) {
-		ad = ad_init(fsp, handle, ADOUBLE_RSRC);
+		ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+			     handle, ADOUBLE_RSRC, fsp);
 		if (ad == NULL) {
 			rc = -1;
 			goto exit;
 		}
-
-		fsp->fh->fd = hostfd;
-
-		rc = ad_fset(ad, fsp);
-		fsp->fh->fd = -1;
+		rc = ad_write(ad, smb_fname->base_name);
 		if (rc != 0) {
 			rc = -1;
 			goto exit;
 		}
-		TALLOC_FREE(ad);
-	}
-
-exit:
-
-	TALLOC_FREE(adpath);
-	TALLOC_FREE(smb_fname_base);
+	} else {
+		ad = ad_alloc(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+			      handle, ADOUBLE_RSRC, fsp);
+		if (ad == NULL) {
+			rc = -1;
+			goto exit;
+		}
+		if (ad_read(ad, smb_fname->base_name) == -1) {
+			rc = -1;
+			goto exit;
+		}
+	}
+
+exit:
+
+	TALLOC_FREE(adpath);
+	TALLOC_FREE(smb_fname_base);
 
 	DEBUG(10, ("fruit_open resource fork: rc=%d, fd=%d\n", rc, hostfd));
 	if (rc != 0) {
@@ -2913,100 +2365,24 @@ exit:
 	return hostfd;
 }
 
-static int fruit_open_rsrc_xattr(vfs_handle_struct *handle,
-				 struct smb_filename *smb_fname,
-				 files_struct *fsp,
-				 int flags,
-				 mode_t mode)
-{
-#ifdef HAVE_ATTROPEN
-	int fd = -1;
-
-	fd = attropen(smb_fname->base_name,
-		      AFPRESOURCE_EA_NETATALK,
-		      flags,
-		      mode);
-	if (fd == -1) {
-		return -1;
-	}
-
-	return fd;
-
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-static int fruit_open_rsrc(vfs_handle_struct *handle,
-			   struct smb_filename *smb_fname,
-			   files_struct *fsp, int flags, mode_t mode)
-{
-	int fd;
-	struct fruit_config_data *config = NULL;
-	struct fio *fio = NULL;
-
-	DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
-
-	switch (config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		fd = fruit_open_rsrc_adouble(handle, smb_fname,
-					     fsp, flags, mode);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		fd = fruit_open_rsrc_xattr(handle, smb_fname,
-					   fsp, flags, mode);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
-		return -1;
-	}
-
-	DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
-
-	if (fd == -1) {
-		return -1;
-	}
-
-	fio = (struct fio *)VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
-	fio->type = ADOUBLE_RSRC;
-	fio->config = config;
-
-	return fd;
-}
-
 static int fruit_open(vfs_handle_struct *handle,
                       struct smb_filename *smb_fname,
                       files_struct *fsp, int flags, mode_t mode)
 {
-	int fd;
-
-	DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
+	DEBUG(10, ("fruit_open called for %s\n",
+		   smb_fname_str_dbg(smb_fname)));
 
 	if (!is_ntfs_stream_smb_fname(smb_fname)) {
 		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
 	}
 
 	if (is_afpinfo_stream(smb_fname)) {
-		fd = fruit_open_meta(handle, smb_fname, fsp, flags, mode);
+		return fruit_open_meta(handle, smb_fname, fsp, flags, mode);
 	} else if (is_afpresource_stream(smb_fname)) {
-		fd = fruit_open_rsrc(handle, smb_fname, fsp, flags, mode);
-	} else {
-		fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+		return fruit_open_rsrc(handle, smb_fname, fsp, flags, mode);
 	}
 
-	DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
-
-	return fd;
+	return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
 }
 
 static int fruit_rename(struct vfs_handle_struct *handle,
@@ -3017,27 +2393,19 @@ static int fruit_rename(struct vfs_handle_struct *handle,
 	char *src_adouble_path = NULL;
 	char *dst_adouble_path = NULL;
 	struct fruit_config_data *config = NULL;
-	struct smb_filename *src_adp_smb_fname = NULL;
-	struct smb_filename *dst_adp_smb_fname = NULL;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
+	rc = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
 
-	if (!VALID_STAT(smb_fname_src->st)) {
-		DBG_ERR("Need valid stat for [%s]\n",
-			smb_fname_str_dbg(smb_fname_src));
-		return -1;
+	if (!VALID_STAT(smb_fname_src->st)
+	    || !S_ISREG(smb_fname_src->st.st_ex_mode)) {
+		return rc;
 	}
 
-	rc = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
-	if (rc != 0) {
-		return -1;
-	}
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-	if ((config->rsrc != FRUIT_RSRC_ADFILE) ||
-	    (!S_ISREG(smb_fname_src->st.st_ex_mode)))
-	{
-		return 0;
+	if (config->rsrc == FRUIT_RSRC_XATTR) {
+		return rc;
 	}
 
 	rc = adouble_path(talloc_tos(), smb_fname_src->base_name,
@@ -3045,271 +2413,93 @@ static int fruit_rename(struct vfs_handle_struct *handle,
 	if (rc != 0) {
 		goto done;
 	}
-	src_adp_smb_fname = synthetic_smb_fname(talloc_tos(),
-						src_adouble_path,
-						NULL, NULL,
-						smb_fname_src->flags);
-	TALLOC_FREE(src_adouble_path);
-	if (src_adp_smb_fname == NULL) {
-		rc = -1;
-		goto done;
-	}
-
 	rc = adouble_path(talloc_tos(), smb_fname_dst->base_name,
 			  &dst_adouble_path);
 	if (rc != 0) {
 		goto done;
 	}
-	dst_adp_smb_fname = synthetic_smb_fname(talloc_tos(),
-						dst_adouble_path,
-						NULL, NULL,
-						smb_fname_dst->flags);
-	TALLOC_FREE(dst_adouble_path);
-	if (dst_adp_smb_fname == NULL) {
-		rc = -1;
-		goto done;
-	}
 
-	DBG_DEBUG("%s -> %s\n",
-		  smb_fname_str_dbg(src_adp_smb_fname),
-		  smb_fname_str_dbg(dst_adp_smb_fname));
+	DEBUG(10, ("fruit_rename: %s -> %s\n",
+		   src_adouble_path, dst_adouble_path));
 
-	rc = SMB_VFS_NEXT_RENAME(handle, src_adp_smb_fname, dst_adp_smb_fname);
+	rc = rename(src_adouble_path, dst_adouble_path);
 	if (errno == ENOENT) {
 		rc = 0;
 	}
 
+	TALLOC_FREE(src_adouble_path);
+	TALLOC_FREE(dst_adouble_path);
+
 done:
-	TALLOC_FREE(src_adp_smb_fname);
-	TALLOC_FREE(dst_adp_smb_fname);
 	return rc;
 }
 
-static int fruit_unlink_meta_stream(vfs_handle_struct *handle,
-				    const struct smb_filename *smb_fname)
-{
-	return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-}
-
-static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
-				      const struct smb_filename *smb_fname)
-{
-	return SMB_VFS_REMOVEXATTR(handle->conn,
-				   smb_fname->base_name,
-				   AFPINFO_EA_NETATALK);
-}
-
-static int fruit_unlink_meta(vfs_handle_struct *handle,
-			     const struct smb_filename *smb_fname)
+static int fruit_unlink(vfs_handle_struct *handle,
+			const struct smb_filename *smb_fname)
 {
+	int rc = -1;
 	struct fruit_config_data *config = NULL;
-	int rc;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data, return -1);
 
-	switch (config->meta) {
-	case FRUIT_META_STREAM:
-		rc = fruit_unlink_meta_stream(handle, smb_fname);
-		break;
-
-	case FRUIT_META_NETATALK:
-		rc = fruit_unlink_meta_netatalk(handle, smb_fname);
-		break;
-
-	default:
-		DBG_ERR("Unsupported meta config [%d]\n", config->meta);
-		return -1;
-	}
-
-	return rc;
-}
-
-static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
-				    const struct smb_filename *smb_fname,
-				    bool force_unlink)
-{
-	int ret;
-
-	if (!force_unlink) {
-		struct smb_filename *smb_fname_cp = NULL;
-		off_t size;
+	if (!is_ntfs_stream_smb_fname(smb_fname)) {
+		char *adp = NULL;
 
-		smb_fname_cp = cp_smb_filename(talloc_tos(), smb_fname);
-		if (smb_fname_cp == 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.
 		 */
-
-		ret = SMB_VFS_NEXT_STAT(handle, smb_fname_cp);
-		if (ret != 0) {
-			TALLOC_FREE(smb_fname_cp);
-			DBG_ERR("stat [%s] failed [%s]\n",
-				smb_fname_str_dbg(smb_fname_cp), strerror(errno));
+		rc = adouble_path(talloc_tos(),
+				  smb_fname->base_name, &adp);
+		if (rc != 0) {
 			return -1;
 		}
 
-		size = smb_fname_cp->st.st_ex_size;
-		TALLOC_FREE(smb_fname_cp);
-
-		if (size > 0) {
-			/* OS X ignores resource fork stream delete requests */
-			return 0;
+		/* FIXME: direct unlink(), missing smb_fname */
+		DBG_DEBUG("fruit_unlink: %s\n", adp);
+		rc = unlink(adp);
+		if ((rc == -1) && (errno == ENOENT)) {
+			rc = 0;
 		}
-	}
 
-	ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-	if ((ret != 0) && (errno == ENOENT) && force_unlink) {
-		ret = 0;
+		TALLOC_FREE(adp);
+		return 0;
 	}
 
-	return ret;
-}
-
-static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
-				     const struct smb_filename *smb_fname,
-				     bool force_unlink)
-{
-	int rc;
-	char *adp = NULL;
-	struct adouble *ad = NULL;
-	struct smb_filename *adp_smb_fname = NULL;
-
-	if (!force_unlink) {
-		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
-			    ADOUBLE_RSRC);
-		if (ad == NULL) {
-			errno = ENOENT;
-			return -1;
-		}
-
-
-		/*
-		 * 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.
-		 */
-
-		if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
-			/* OS X ignores resource fork stream delete requests */
-			TALLOC_FREE(ad);
-			return 0;
+	if (is_afpinfo_stream(smb_fname)) {
+		if (config->meta == FRUIT_META_STREAM) {
+			rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+		} else {
+			rc = SMB_VFS_REMOVEXATTR(handle->conn,
+						 smb_fname->base_name,
+						 AFPINFO_EA_NETATALK);
 		}
 
-		TALLOC_FREE(ad);
-	}
-
-	rc = adouble_path(talloc_tos(), smb_fname->base_name, &adp);
-	if (rc != 0) {
-		return -1;
+		return rc;
 	}
 
-	adp_smb_fname = synthetic_smb_fname(talloc_tos(), adp,
-					    NULL, NULL,
-					    smb_fname->flags);
-	TALLOC_FREE(adp);
-	if (adp_smb_fname == NULL) {
-		return -1;
+	if (is_afpresource_stream(smb_fname)) {
+		/* OS X ignores deletes on the AFP_Resource stream */
+		return 0;
 	}
 
-	rc = SMB_VFS_NEXT_UNLINK(handle, adp_smb_fname);
-	TALLOC_FREE(adp_smb_fname);
-	if ((rc != 0) && (errno == ENOENT) && force_unlink) {
-		rc = 0;
-	}
+	return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
 
-	return rc;
-}
 
-static int fruit_unlink_rsrc_xattr(vfs_handle_struct *handle,
-				   const struct smb_filename *smb_fname,
-				   bool force_unlink)
-{
-	/* Nothing to do here, removing the file will remove the xattr */
 	return 0;
 }
 
-static int fruit_unlink_rsrc(vfs_handle_struct *handle,
-			     const struct smb_filename *smb_fname,
-			     bool force_unlink)
-{
-	struct fruit_config_data *config = NULL;
-	int rc;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
-
-	switch (config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		rc = fruit_unlink_rsrc_stream(handle, smb_fname, force_unlink);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		rc = fruit_unlink_rsrc_adouble(handle, smb_fname, force_unlink);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		rc = fruit_unlink_rsrc_xattr(handle, smb_fname, force_unlink);
-		break;
-
-	default:
-		DBG_ERR("Unsupported rsrc config [%d]\n", config->rsrc);
-		return -1;
-	}
-
-	return rc;
-}
-
-static int fruit_unlink(vfs_handle_struct *handle,
-			const struct smb_filename *smb_fname)
-{
-	int rc;
-	struct fruit_config_data *config = NULL;
-	struct smb_filename *rsrc_smb_fname = NULL;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
-
-	if (is_afpinfo_stream(smb_fname)) {
-		return fruit_unlink_meta(handle, smb_fname);
-	} else if (is_afpresource_stream(smb_fname)) {
-		return fruit_unlink_rsrc(handle, smb_fname, false);
-	} if (is_ntfs_stream_smb_fname(smb_fname)) {
-		return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-	}
-
-	/*
-	 * A request to delete the base file. Because 0 byte resource
-	 * fork streams are not listed by fruit_streaminfo,
-	 * delete_all_streams() can't remove 0 byte resource fork
-	 * streams, so we have to cleanup this here.
-	 */
-	rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
-					     smb_fname->base_name,
-					     AFPRESOURCE_STREAM_NAME,
-					     NULL,
-					     smb_fname->flags);
-	if (rsrc_smb_fname == NULL) {
-		return -1;
-	}
-
-	rc = fruit_unlink_rsrc(handle, rsrc_smb_fname, true);
-	if ((rc != 0) && (errno != ENOENT)) {
-		DBG_ERR("Forced unlink of [%s] failed [%s]\n",
-			smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
-		TALLOC_FREE(rsrc_smb_fname);
-		return -1;
-	}
-	TALLOC_FREE(rsrc_smb_fname);
-
-	return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-}
-
 static int fruit_chmod(vfs_handle_struct *handle,
 		       const struct smb_filename *smb_fname,
 		       mode_t mode)
@@ -3317,6 +2507,7 @@ static int fruit_chmod(vfs_handle_struct *handle,
 	int rc = -1;
 	char *adp = NULL;
 	struct fruit_config_data *config = NULL;
+	SMB_STRUCT_STAT sb;
 	const char *path = smb_fname->base_name;
 	struct smb_filename *smb_fname_adp = NULL;
 
@@ -3328,16 +2519,14 @@ static int fruit_chmod(vfs_handle_struct *handle,
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data, return -1);
 
-	if (config->rsrc != FRUIT_RSRC_ADFILE) {
-		return 0;
-	}
-
-	if (!VALID_STAT(smb_fname->st)) {
+	if (config->rsrc == FRUIT_RSRC_XATTR) {
 		return 0;
 	}
 
-	if (!S_ISREG(smb_fname->st.st_ex_mode)) {
-		return 0;
+	/* FIXME: direct sys_lstat(), missing smb_fname */
+	rc = sys_lstat(path, &sb, false);
+	if (rc != 0 || !S_ISREG(sb.st_ex_mode)) {
+		return rc;
 	}
 
 	rc = adouble_path(talloc_tos(), path, &adp);
@@ -3377,6 +2566,7 @@ static int fruit_chown(vfs_handle_struct *handle,
 	char *adp = NULL;
 	struct fruit_config_data *config = NULL;
 	struct smb_filename *adp_smb_fname = NULL;
+	SMB_STRUCT_STAT sb;
 
 	rc = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
 	if (rc != 0) {
@@ -3386,16 +2576,14 @@ static int fruit_chown(vfs_handle_struct *handle,
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data, return -1);
 
-	if (config->rsrc != FRUIT_RSRC_ADFILE) {
-		return 0;
-	}
-
-	if (!VALID_STAT(smb_fname->st)) {
-		return 0;
+	if (config->rsrc == FRUIT_RSRC_XATTR) {
+		return rc;
 	}
 
-	if (!S_ISREG(smb_fname->st.st_ex_mode)) {
-		return 0;
+	/* FIXME: direct sys_lstat(), need non-const smb_fname */
+	rc = sys_lstat(smb_fname->base_name, &sb, false);
+	if (rc != 0 || !S_ISREG(sb.st_ex_mode)) {
+		return rc;
 	}
 
 	rc = adouble_path(talloc_tos(), smb_fname->base_name, &adp);
@@ -3433,11 +2621,12 @@ static int fruit_rmdir(struct vfs_handle_struct *handle,
 	DIR *dh = NULL;
 	struct dirent *de;
 	struct fruit_config_data *config;
+	const char *path = smb_fname->base_name;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config,
 				struct fruit_config_data, return -1);
 
-	if (config->rsrc != FRUIT_RSRC_ADFILE) {
+	if (!handle->conn->cwd || !path || (config->rsrc == FRUIT_RSRC_XATTR)) {
 		goto exit_rmdir;
 	}
 
@@ -3445,58 +2634,24 @@ static int fruit_rmdir(struct vfs_handle_struct *handle,
 	 * Due to there is no way to change bDeleteVetoFiles variable
 	 * from this module, need to clean up ourselves
 	 */
-
-	dh = SMB_VFS_OPENDIR(handle->conn, smb_fname, NULL, 0);
+	dh = opendir(path);
 	if (dh == NULL) {
 		goto exit_rmdir;
 	}
 
-	while ((de = SMB_VFS_READDIR(handle->conn, dh, NULL)) != NULL) {
-		int match;
-		struct adouble *ad = NULL;
-		char *p = NULL;
-		struct smb_filename *ad_smb_fname = NULL;
-		int ret;
-
-		match = strncmp(de->d_name,
-				ADOUBLE_NAME_PREFIX,
-				strlen(ADOUBLE_NAME_PREFIX));
-		if (match != 0) {
-			continue;
-		}
-
-		p = talloc_asprintf(talloc_tos(), "%s/%s",
-				    smb_fname->base_name, de->d_name);
-		if (p == NULL) {
-			DBG_ERR("talloc_asprintf failed\n");
-			return -1;
-		}
-
-		/*
-		 * Check whether it's a valid AppleDouble file, if
-		 * yes, delete it, ignore it otherwise.
-		 */
-		ad = ad_get(talloc_tos(), handle, p, ADOUBLE_RSRC);
-		if (ad == NULL) {
+	while ((de = readdir(dh)) != NULL) {
+		if ((strncmp(de->d_name,
+			     ADOUBLE_NAME_PREFIX,
+			     strlen(ADOUBLE_NAME_PREFIX))) == 0) {
+			char *p = talloc_asprintf(talloc_tos(),
+						  "%s/%s",
+						  path, de->d_name);
+			if (p == NULL) {
+				goto exit_rmdir;
+			}
+			DEBUG(10, ("fruit_rmdir: delete %s\n", p));
+			(void)unlink(p);
 			TALLOC_FREE(p);
-			continue;
-		}
-		TALLOC_FREE(ad);
-
-		ad_smb_fname = synthetic_smb_fname(talloc_tos(), p,
-						    NULL, NULL,
-						    smb_fname->flags);
-		TALLOC_FREE(p);
-		if (ad_smb_fname == NULL) {
-			DBG_ERR("synthetic_smb_fname failed\n");
-			return -1;
-		}
-
-		ret = SMB_VFS_NEXT_UNLINK(handle, ad_smb_fname);
-		TALLOC_FREE(ad_smb_fname);
-		if (ret != 0) {
-			DBG_ERR("Deleting [%s] failed\n",
-				smb_fname_str_dbg(ad_smb_fname));
 		}
 	}
 
@@ -3507,424 +2662,243 @@ exit_rmdir:
 	return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
 }
 
-static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
-				       files_struct *fsp, void *data,
-				       size_t n, off_t offset)
-{
-	ssize_t nread;
-	int ret;
-
-	nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-
-	if (nread == n) {
-		return nread;
-	}
-
-	DBG_ERR("Removing [%s] after short read [%zd]\n",
-		fsp_str_dbg(fsp), nread);
-
-	ret = SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name);
-	if (ret != 0) {
-		DBG_ERR("Removing [%s] failed\n", fsp_str_dbg(fsp));
-		return -1;
-	}
-
-	errno = EINVAL;
-	return -1;
-}
-
-static ssize_t fruit_pread_meta_adouble(vfs_handle_struct *handle,
-					files_struct *fsp, void *data,
-					size_t n, off_t offset)
+static ssize_t fruit_pread(vfs_handle_struct *handle,
+			   files_struct *fsp, void *data,
+			   size_t n, off_t offset)
 {
+	int rc = 0;
+        struct adouble *ad = (struct adouble *)VFS_FETCH_FSP_EXTENSION(
+		handle, fsp);
+	struct fruit_config_data *config = NULL;
 	AfpInfo *ai = NULL;
-	struct adouble *ad = NULL;
-	char afpinfo_buf[AFP_INFO_SIZE];
-	char *p = NULL;
-	ssize_t nread;
-
-	ai = afpinfo_new(talloc_tos());
-	if (ai == NULL) {
-		return -1;
-	}
-
-	ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
-	if (ad == NULL) {
-		nread = -1;
-		goto fail;
-	}
-
-	p = ad_get_entry(ad, ADEID_FINDERI);
-	if (p == NULL) {
-		DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
-		nread = -1;
-		goto fail;
-	}
-
-	memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI);
-
-	nread = afpinfo_pack(ai, afpinfo_buf);
-	if (nread != AFP_INFO_SIZE) {
-		nread = -1;
-		goto fail;
-	}
-
-	memcpy(data, afpinfo_buf, n);
-	nread = n;
-
-fail:
-	TALLOC_FREE(ai);
-	return nread;
-}
+	ssize_t len = -1;
+	char *name = NULL;
+	char *tmp_base_name = NULL;
+	NTSTATUS status;
 
-static ssize_t fruit_pread_meta(vfs_handle_struct *handle,
-				files_struct *fsp, void *data,
-				size_t n, off_t offset)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	ssize_t nread;
-	ssize_t to_return;
+	DEBUG(10, ("fruit_pread: offset=%d, size=%d\n", (int)offset, (int)n));
 
-	/*
-	 * OS X has a off-by-1 error in the offset calculation, so we're
-	 * bug compatible here. It won't hurt, as any relevant real
-	 * world read requests from the AFP_AfpInfo stream will be
-	 * offset=0 n=60. offset is ignored anyway, see below.
-	 */
-	if ((offset < 0) || (offset >= AFP_INFO_SIZE + 1)) {
-		return 0;
+	if (!fsp->base_fsp) {
+		return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
 	}
 
-	/* Yes, macOS always reads from offset 0 */
-	offset = 0;
-	to_return = MIN(n, AFP_INFO_SIZE);
-
-	switch (fio->config->meta) {
-	case FRUIT_META_STREAM:
-		nread = fruit_pread_meta_stream(handle, fsp, data,
-						to_return, offset);
-		break;
-
-	case FRUIT_META_NETATALK:
-		nread = fruit_pread_meta_adouble(handle, fsp, data,
-						 to_return, offset);
-		break;
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
-		return -1;
+	/* fsp_name is not converted with vfs_catia */
+	tmp_base_name = fsp->base_fsp->fsp_name->base_name;
+	status = SMB_VFS_TRANSLATE_NAME(handle->conn,
+					fsp->base_fsp->fsp_name->base_name,
+					vfs_translate_to_unix,
+					talloc_tos(), &name);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+		name = talloc_strdup(talloc_tos(), tmp_base_name);
+		if (name == NULL) {
+			rc = -1;
+			goto exit;
+		}
+	} else if (!NT_STATUS_IS_OK(status)) {
+		errno = map_errno_from_nt_status(status);
+		rc = -1;
+		goto exit;
 	}
+	fsp->base_fsp->fsp_name->base_name = name;
 
-	return nread;
-}
-
-static ssize_t fruit_pread_rsrc_stream(vfs_handle_struct *handle,
-				       files_struct *fsp, void *data,
-				       size_t n, off_t offset)
-{
-	return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-}
-
-static ssize_t fruit_pread_rsrc_xattr(vfs_handle_struct *handle,
-				      files_struct *fsp, void *data,
-				      size_t n, off_t offset)
-{
-	return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-}
-
-static ssize_t fruit_pread_rsrc_adouble(vfs_handle_struct *handle,
-					files_struct *fsp, void *data,
-					size_t n, off_t offset)
-{
-	struct adouble *ad = NULL;
-	ssize_t nread;
-
-	ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
 	if (ad == NULL) {
-		return -1;
+		len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+		if (len == -1) {
+			rc = -1;
+			goto exit;
+		}
+		goto exit;
 	}
 
-	nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n,
-				   offset + ad_getentryoff(ad, ADEID_RFORK));
-
-	TALLOC_FREE(ad);
-	return nread;
-}
-
-static ssize_t fruit_pread_rsrc(vfs_handle_struct *handle,
-				files_struct *fsp, void *data,
-				size_t n, off_t offset)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	ssize_t nread;
-
-	switch (fio->config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		nread = fruit_pread_rsrc_stream(handle, fsp, data, n, offset);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		nread = fruit_pread_rsrc_adouble(handle, fsp, data, n, offset);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		nread = fruit_pread_rsrc_xattr(handle, fsp, data, n, offset);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
-		return -1;
+	if (!fruit_fsp_recheck(ad, fsp)) {
+		rc = -1;
+		goto exit;
 	}
 
-	return nread;
-}
+	if (ad->ad_type == ADOUBLE_META) {
+		char afpinfo_buf[AFP_INFO_SIZE];
+		size_t to_return;
 
-static ssize_t fruit_pread(vfs_handle_struct *handle,
-			   files_struct *fsp, void *data,
-			   size_t n, off_t offset)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	ssize_t nread;
-
-	DBG_DEBUG("Path [%s] offset=%zd, size=%zd\n",
-		  fsp_str_dbg(fsp), offset, n);
-
-	if (fio == NULL) {
-		return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
-	}
-
-	if (fio->type == ADOUBLE_META) {
-		nread = fruit_pread_meta(handle, fsp, data, n, offset);
-	} else {
-		nread = fruit_pread_rsrc(handle, fsp, data, n, offset);
-	}
+		/*
+		 * OS X has a off-by-1 error in the offset calculation, so we're
+		 * bug compatible here. It won't hurt, as any relevant real
+		 * world read requests from the AFP_AfpInfo stream will be
+		 * offset=0 n=60. offset is ignored anyway, see below.
+		 */
+		if ((offset < 0) || (offset >= AFP_INFO_SIZE + 1)) {
+			len = 0;
+			rc = 0;
+			goto exit;
+		}
 
-	DBG_DEBUG("Path [%s] nread [%zd]\n", fsp_str_dbg(fsp), nread);
-	return nread;
-}
+		to_return = MIN(n, AFP_INFO_SIZE);
 
-static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
-					files_struct *fsp, const void *data,
-					size_t n, off_t offset)
-{
-	AfpInfo *ai = NULL;
-	int ret;
+		ai = afpinfo_new(talloc_tos());
+		if (ai == NULL) {
+			rc = -1;
+			goto exit;
+		}
 
-	ai = afpinfo_unpack(talloc_tos(), data);
-	if (ai == NULL) {
-		return -1;
-	}
+		len = ad_read(ad, fsp->base_fsp->fsp_name->base_name);
+		if (len == -1) {
+			rc = -1;
+			goto exit;
+		}
 
-	if (ai_empty_finderinfo(ai)) {
-		ret = SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name);
-		if (ret != 0 && errno != ENOENT && errno != ENOATTR) {
-			DBG_ERR("Can't delete metadata for %s: %s\n",
-				fsp_str_dbg(fsp), strerror(errno));
-			TALLOC_FREE(ai);
-			return -1;
+		memcpy(&ai->afpi_FinderInfo[0],
+		       ad_entry(ad, ADEID_FINDERI),
+		       ADEDLEN_FINDERI);
+		len = afpinfo_pack(ai, afpinfo_buf);
+		if (len != AFP_INFO_SIZE) {
+			rc = -1;
+			goto exit;
 		}
 
-		return n;
+		/*
+		 * OS X ignores offset when reading from AFP_AfpInfo stream!
+		 */
+		memcpy(data, afpinfo_buf, to_return);
+		len = to_return;
+	} else {
+		len = SMB_VFS_NEXT_PREAD(
+			handle, fsp, data, n,
+			offset + ad_getentryoff(ad, ADEID_RFORK));
+		if (len == -1) {
+			rc = -1;
+			goto exit;
+		}
 	}
-
-	return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+exit:
+	fsp->base_fsp->fsp_name->base_name = tmp_base_name;
+	TALLOC_FREE(name);
+	TALLOC_FREE(ai);
+	if (rc != 0) {
+		len = -1;
+	}
+	DEBUG(10, ("fruit_pread: rc=%d, len=%zd\n", rc, len));
+	return len;
 }
 
-static ssize_t fruit_pwrite_meta_netatalk(vfs_handle_struct *handle,
-					  files_struct *fsp, const void *data,
-					  size_t n, off_t offset)
+static ssize_t fruit_pwrite(vfs_handle_struct *handle,
+			    files_struct *fsp, const void *data,
+			    size_t n, off_t offset)
 {
-	struct adouble *ad = NULL;
+	int rc = 0;
+	struct adouble *ad = (struct adouble *)VFS_FETCH_FSP_EXTENSION(
+		handle, fsp);
+	struct fruit_config_data *config = NULL;
 	AfpInfo *ai = NULL;
-	char *p = NULL;
-	int ret;
+	ssize_t len;
+	char *name = NULL;
+	char *tmp_base_name = NULL;
+	NTSTATUS status;
 
-	ai = afpinfo_unpack(talloc_tos(), data);
-	if (ai == NULL) {
-		return -1;
+	DEBUG(10, ("fruit_pwrite: offset=%d, size=%d\n", (int)offset, (int)n));
+
+	if (!fsp->base_fsp) {
+		return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
 	}
 
-	if (ai_empty_finderinfo(ai)) {
-		ret = SMB_VFS_REMOVEXATTR(handle->conn,
-					  fsp->fsp_name->base_name,
-					  AFPINFO_EA_NETATALK);
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-		if (ret != 0 && errno != ENOENT && errno != ENOATTR) {
-			DBG_ERR("Can't delete metadata for %s: %s\n",
-				fsp_str_dbg(fsp), strerror(errno));
-			return -1;
+	tmp_base_name = fsp->base_fsp->fsp_name->base_name;
+	status = SMB_VFS_TRANSLATE_NAME(handle->conn,
+					fsp->base_fsp->fsp_name->base_name,
+					vfs_translate_to_unix,
+					talloc_tos(), &name);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+		name = talloc_strdup(talloc_tos(), tmp_base_name);
+		if (name == NULL) {
+			rc = -1;
+			goto exit;
 		}
-
-		return n;
+	} else if (!NT_STATUS_IS_OK(status)) {
+		errno = map_errno_from_nt_status(status);
+		rc = -1;
+		goto exit;
 	}
+	fsp->base_fsp->fsp_name->base_name = name;
 
-	ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
 	if (ad == NULL) {
-		ad = ad_init(talloc_tos(), handle, ADOUBLE_META);
-		if (ad == NULL) {
-			return -1;
+		len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+		if (len != n) {
+			rc = -1;
+			goto exit;
 		}
+		goto exit;
 	}
-	p = ad_get_entry(ad, ADEID_FINDERI);
-	if (p == NULL) {
-		DBG_ERR("No ADEID_FINDERI for [%s]\n", fsp_str_dbg(fsp));
-		TALLOC_FREE(ad);
-		return -1;
-	}
-
-	memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
-
-	ret = ad_fset(ad, fsp);
-	if (ret != 0) {
-		DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
-		TALLOC_FREE(ad);
-		return -1;
-	}
-
-	TALLOC_FREE(ad);
-	return n;
-}
-
-static ssize_t fruit_pwrite_meta(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);
-	ssize_t nwritten;
-
-	/*
-	 * Writing an all 0 blob to the metadata stream
-	 * results in the stream being removed on a macOS
-	 * server. This ensures we behave the same and it
-	 * verified by the "delete AFP_AfpInfo by writing all
-	 * 0" test.
-	 */
-	if (n != AFP_INFO_SIZE || offset != 0) {
-		DBG_ERR("unexpected offset=%jd or size=%jd\n",
-			(intmax_t)offset, (intmax_t)n);
-		return -1;
-	}
-
-	switch (fio->config->meta) {
-	case FRUIT_META_STREAM:
-		nwritten = fruit_pwrite_meta_stream(handle, fsp, data,
-						    n, offset);
-		break;
 
-	case FRUIT_META_NETATALK:
-		nwritten = fruit_pwrite_meta_netatalk(handle, fsp, data,
-						      n, offset);
-		break;
-
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
-		return -1;
+	if (!fruit_fsp_recheck(ad, fsp)) {
+		rc = -1;
+		goto exit;
 	}
 
-	return nwritten;
-}
-
-static ssize_t fruit_pwrite_rsrc_stream(vfs_handle_struct *handle,
-					files_struct *fsp, const void *data,
-					size_t n, off_t offset)
-{
-	return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
-}
-
-static ssize_t fruit_pwrite_rsrc_xattr(vfs_handle_struct *handle,
-				       files_struct *fsp, const void *data,
-				       size_t n, off_t offset)
-{
-	return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
-}
-
-static ssize_t fruit_pwrite_rsrc_adouble(vfs_handle_struct *handle,
-					 files_struct *fsp, const void *data,
-					 size_t n, off_t offset)
-{
-	struct adouble *ad = NULL;
-	ssize_t nwritten;
-	int ret;
-
-	ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
-	if (ad == NULL) {
-		DBG_ERR("ad_get [%s] failed\n", fsp_str_dbg(fsp));
-		return -1;
-	}
+	if (ad->ad_type == ADOUBLE_META) {
+		if (n != AFP_INFO_SIZE || offset != 0) {
+			DEBUG(1, ("unexpected offset=%jd or size=%jd\n",
+				  (intmax_t)offset, (intmax_t)n));
+			rc = -1;
+			goto exit;
+		}
+		ai = afpinfo_unpack(talloc_tos(), data);
+		if (ai == NULL) {
+			rc = -1;
+			goto exit;
+		}
+		memcpy(ad_entry(ad, ADEID_FINDERI),
+		       &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI);
+		if (empty_finderinfo(ad)) {
+			/* Discard metadata */
+			if (config->meta == FRUIT_META_STREAM) {
+				rc = SMB_VFS_FTRUNCATE(fsp, 0);
+			} else {
+				rc = SMB_VFS_REMOVEXATTR(handle->conn,
+							 fsp->fsp_name->base_name,
+							 AFPINFO_EA_NETATALK);
+			}
+			if (rc != 0 && errno != ENOENT && errno != ENOATTR) {
+				DBG_WARNING("Can't delete metadata for %s: %s\n",
+					    fsp->fsp_name->base_name, strerror(errno));
+				goto exit;
+			}
+			rc = 0;
+			goto exit;
+		}
+		rc = ad_write(ad, name);
+	} else {
+		len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n,
+                                   offset + ad_getentryoff(ad, ADEID_RFORK));
+		if (len != n) {
+			rc = -1;
+			goto exit;
+		}
 
-	nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n,
-				       offset + ad_getentryoff(ad, ADEID_RFORK));
-	if (nwritten != n) {
-		DBG_ERR("Short write on [%s] [%zd/%zd]\n",
-			fsp_str_dbg(fsp), nwritten, n);
-		TALLOC_FREE(ad);
-		return -1;
-	}
+		if (config->rsrc == FRUIT_RSRC_ADFILE) {
+			rc = ad_read(ad, name);
+			if (rc == -1) {
+				goto exit;
+			}
+			rc = 0;
 
-	if ((n + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
-		ad_setentrylen(ad, ADEID_RFORK, n + offset);
-		ret = ad_fset(ad, fsp);
-		if (ret != 0) {
-			DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
-			TALLOC_FREE(ad);
-			return -1;
+			if ((len + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
+				ad_setentrylen(ad, ADEID_RFORK, len + offset);
+				rc = ad_write(ad, name);
+			}
 		}
 	}
 
-	TALLOC_FREE(ad);
-	return n;
-}
-
-static ssize_t fruit_pwrite_rsrc(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);
-	ssize_t nwritten;
-
-	switch (fio->config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		nwritten = fruit_pwrite_rsrc_stream(handle, fsp, data, n, offset);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		nwritten = fruit_pwrite_rsrc_adouble(handle, fsp, data, n, offset);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		nwritten = fruit_pwrite_rsrc_xattr(handle, fsp, data, n, offset);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
+exit:
+	fsp->base_fsp->fsp_name->base_name = tmp_base_name;
+	TALLOC_FREE(name);
+	TALLOC_FREE(ai);
+	if (rc != 0) {
 		return -1;
 	}
-
-	return nwritten;
-}
-
-static ssize_t fruit_pwrite(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);
-	ssize_t nwritten;
-
-	DBG_DEBUG("Path [%s] offset=%zd, size=%zd\n",
-		  fsp_str_dbg(fsp), offset, n);
-
-	if (fio == NULL) {
-		return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
-	}
-
-	if (fio->type == ADOUBLE_META) {
-		nwritten = fruit_pwrite_meta(handle, fsp, data, n, offset);
-	} else {
-		nwritten = fruit_pwrite_rsrc(handle, fsp, data, n, offset);
-	}
-
-	DBG_DEBUG("Path [%s] nwritten=%zd\n", fsp_str_dbg(fsp), nwritten);
-	return nwritten;
+	return n;
 }
 
 /**
@@ -3940,32 +2914,17 @@ static int fruit_stat_base(vfs_handle_struct *handle,
 	tmp_stream_name = smb_fname->stream_name;
 	smb_fname->stream_name = NULL;
 	if (follow_links) {
-		rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
-	} else {
-		rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-	}
-	smb_fname->stream_name = tmp_stream_name;
-	return rc;
-}
-
-static int fruit_stat_meta_stream(vfs_handle_struct *handle,
-				  struct smb_filename *smb_fname,
-				  bool follow_links)
-{
-	int ret;
-
-	if (follow_links) {
-		ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+		rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
 	} else {
-		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+		rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
 	}
-
-	return ret;
+	smb_fname->stream_name = tmp_stream_name;
+	return rc;
 }
 
-static int fruit_stat_meta_netatalk(vfs_handle_struct *handle,
-				    struct smb_filename *smb_fname,
-				    bool follow_links)
+static int fruit_stat_meta(vfs_handle_struct *handle,
+			   struct smb_filename *smb_fname,
+			   bool follow_links)
 {
 	struct adouble *ad = NULL;
 
@@ -3988,39 +2947,15 @@ static int fruit_stat_meta_netatalk(vfs_handle_struct *handle,
 	return 0;
 }
 
-static int fruit_stat_meta(vfs_handle_struct *handle,
+static int fruit_stat_rsrc(vfs_handle_struct *handle,
 			   struct smb_filename *smb_fname,
 			   bool follow_links)
-{
-	struct fruit_config_data *config = NULL;
-	int ret;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
 
-	switch (config->meta) {
-	case FRUIT_META_STREAM:
-		ret = fruit_stat_meta_stream(handle, smb_fname, follow_links);
-		break;
-
-	case FRUIT_META_NETATALK:
-		ret = fruit_stat_meta_netatalk(handle, smb_fname, follow_links);
-		break;
-
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", config->meta);
-		return -1;
-	}
-
-	return ret;
-}
-
-static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle,
-				    struct smb_filename *smb_fname,
-				    bool follow_links)
 {
 	struct adouble *ad = NULL;
-	int ret;
+
+	DEBUG(10, ("fruit_stat_rsrc called for %s\n",
+		   smb_fname_str_dbg(smb_fname)));
 
 	ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_RSRC);
 	if (ad == NULL) {
@@ -4029,8 +2964,7 @@ static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle,
 	}
 
 	/* Populate the stat struct with info from the base file. */
-	ret = fruit_stat_base(handle, smb_fname, follow_links);
-	if (ret != 0) {
+	if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
 		TALLOC_FREE(ad);
 		return -1;
 	}
@@ -4042,96 +2976,6 @@ static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle,
 	return 0;
 }
 
-static int fruit_stat_rsrc_stream(vfs_handle_struct *handle,
-				  struct smb_filename *smb_fname,
-				  bool follow_links)
-{
-	int ret;
-
-	if (follow_links) {
-		ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-	} else {
-		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-	}
-
-	return ret;
-}
-
-static int fruit_stat_rsrc_xattr(vfs_handle_struct *handle,
-				 struct smb_filename *smb_fname,
-				 bool follow_links)
-{
-#ifdef HAVE_ATTROPEN
-	int ret;
-	int fd = -1;
-
-	/* Populate the stat struct with info from the base file. */
-	ret = fruit_stat_base(handle, smb_fname, follow_links);
-	if (ret != 0) {
-		return -1;
-	}
-
-	fd = attropen(smb_fname->base_name,
-		      AFPRESOURCE_EA_NETATALK,
-		      O_RDONLY);
-	if (fd == -1) {
-		return 0;
-	}
-
-	ret = sys_fstat(fd, &smb_fname->st, false);
-	if (ret != 0) {
-		close(fd);
-		DBG_ERR("fstat [%s:%s] failed\n", smb_fname->base_name,
-			AFPRESOURCE_EA_NETATALK);
-		return -1;
-	}
-	close(fd);
-	fd = -1;
-
-	smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
-					      smb_fname->stream_name);
-
-	return ret;
-
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-
-static int fruit_stat_rsrc(vfs_handle_struct *handle,
-			   struct smb_filename *smb_fname,
-			   bool follow_links)
-{
-	struct fruit_config_data *config = NULL;
-	int ret;
-
-	DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config,
-				struct fruit_config_data, return -1);
-
-	switch (config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		ret = fruit_stat_rsrc_stream(handle, smb_fname, follow_links);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		ret = fruit_stat_rsrc_xattr(handle, smb_fname, follow_links);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		ret = fruit_stat_rsrc_netatalk(handle, smb_fname, follow_links);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
-		return -1;
-	}
-
-	return ret;
-}
-
 static int fruit_stat(vfs_handle_struct *handle,
 		      struct smb_filename *smb_fname)
 {
@@ -4171,462 +3015,169 @@ static int fruit_stat(vfs_handle_struct *handle,
 		smb_fname->st.st_ex_blocks =
 			smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
 	}
-	return rc;
-}
-
-static int fruit_lstat(vfs_handle_struct *handle,
-		       struct smb_filename *smb_fname)
-{
-	int rc = -1;
-
-	DEBUG(10, ("fruit_lstat called for %s\n",
-		   smb_fname_str_dbg(smb_fname)));
-
-	if (!is_ntfs_stream_smb_fname(smb_fname)
-	    || is_ntfs_default_stream_smb_fname(smb_fname)) {
-		rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-		if (rc == 0) {
-			update_btime(handle, smb_fname);
-		}
-		return rc;
-	}
-
-	if (is_afpinfo_stream(smb_fname)) {
-		rc = fruit_stat_meta(handle, smb_fname, false);
-	} else if (is_afpresource_stream(smb_fname)) {
-		rc = fruit_stat_rsrc(handle, smb_fname, false);
-	} else {
-		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-	}
-
-	if (rc == 0) {
-		update_btime(handle, smb_fname);
-		smb_fname->st.st_ex_mode &= ~S_IFMT;
-		smb_fname->st.st_ex_mode |= S_IFREG;
-		smb_fname->st.st_ex_blocks =
-			smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
-	}
-	return rc;
-}
-
-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);
-}
-
-static int fruit_fstat_meta_netatalk(vfs_handle_struct *handle,
-				     files_struct *fsp,
-				     SMB_STRUCT_STAT *sbuf)
-{
-	int ret;
-
-	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;
-}
-
-static int fruit_fstat_meta(vfs_handle_struct *handle,
-			    files_struct *fsp,
-			    SMB_STRUCT_STAT *sbuf)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	int ret;
-
-	if (fio == NULL) {
-		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-	}
-
-	DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
-
-	switch (fio->config->meta) {
-	case FRUIT_META_STREAM:
-		ret = fruit_fstat_meta_stream(handle, fsp, sbuf);
-		break;
-
-	case FRUIT_META_NETATALK:
-		ret = fruit_fstat_meta_netatalk(handle, fsp, sbuf);
-		break;
-
-	default:
-		DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta);
-		return -1;
-	}
-
-	DBG_DEBUG("Path [%s] ret [%d]\n", fsp_str_dbg(fsp), ret);
-	return ret;
-}
-
-static int fruit_fstat_rsrc_xattr(vfs_handle_struct *handle,
-				  files_struct *fsp,
-				  SMB_STRUCT_STAT *sbuf)
-{
-	return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-}
-
-static int fruit_fstat_rsrc_stream(vfs_handle_struct *handle,
-				   files_struct *fsp,
-				   SMB_STRUCT_STAT *sbuf)
-{
-	return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-}
-
-static int fruit_fstat_rsrc_adouble(vfs_handle_struct *handle,
-				    files_struct *fsp,
-				    SMB_STRUCT_STAT *sbuf)
-{
-	struct adouble *ad = NULL;
-	int ret;
-
-	/* Populate the stat struct with info from the base file. */
-	ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
-	if (ret == -1) {
-		return -1;
-	}
-
-	ad = ad_get(talloc_tos(), handle,
-		    fsp->base_fsp->fsp_name->base_name,
-		    ADOUBLE_RSRC);
-	if (ad == NULL) {
-		DBG_ERR("ad_get [%s] failed [%s]\n",
-			fsp_str_dbg(fsp), strerror(errno));
-		return -1;
-	}
-
-	*sbuf = fsp->base_fsp->fsp_name->st;
-	sbuf->st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
-	sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
-
-	TALLOC_FREE(ad);
-	return 0;
-}
-
-static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp,
-			    SMB_STRUCT_STAT *sbuf)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	int ret;
-
-	switch (fio->config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		ret = fruit_fstat_rsrc_stream(handle, fsp, sbuf);
-		break;
-
-	case FRUIT_RSRC_ADFILE:
-		ret = fruit_fstat_rsrc_adouble(handle, fsp, sbuf);
-		break;
-
-	case FRUIT_RSRC_XATTR:
-		ret = fruit_fstat_rsrc_xattr(handle, fsp, sbuf);
-		break;
-
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
-		return -1;
-	}
-
-	return ret;
-}
-
-static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
-		       SMB_STRUCT_STAT *sbuf)
-{
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	int rc;
-
-	if (fio == NULL) {
-		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-	}
-
-	DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
-
-	if (fio->type == ADOUBLE_META) {
-		rc = fruit_fstat_meta(handle, fsp, sbuf);
-	} else {
-		rc = fruit_fstat_rsrc(handle, fsp, sbuf);
-	}
-
-	if (rc == 0) {
-		sbuf->st_ex_mode &= ~S_IFMT;
-		sbuf->st_ex_mode |= S_IFREG;
-		sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
-	}
-
-	DBG_DEBUG("Path [%s] rc [%d] size [%zd]\n",
-		  fsp_str_dbg(fsp), rc, sbuf->st_ex_size);
-	return rc;
-}
-
-static NTSTATUS fruit_streaminfo_meta_stream(
-	vfs_handle_struct *handle,
-	struct files_struct *fsp,
-	const struct smb_filename *smb_fname,
-	TALLOC_CTX *mem_ctx,
-	unsigned int *pnum_streams,
-	struct stream_struct **pstreams)
-{
-	struct stream_struct *stream = *pstreams;
-	unsigned int num_streams = *pnum_streams;
-	struct smb_filename *sname = NULL;
-	int i;
-	int ret;
-	bool ok;
-
-	for (i = 0; i < num_streams; i++) {
-		if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
-			break;
-		}
-	}
-
-	if (i == num_streams) {
-		return NT_STATUS_OK;
-	}
-
-	if (stream[i].size == AFP_INFO_SIZE) {
-		return NT_STATUS_OK;
-	}
-
-	DBG_ERR("Removing invalid AFPINFO_STREAM size [%zd] from [%s]\n",
-		stream[i].size, smb_fname_str_dbg(smb_fname));
-
-	ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams, AFPINFO_STREAM);
-	if (!ok) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	sname = synthetic_smb_fname(talloc_tos(),
-				    smb_fname->base_name,
-				    AFPINFO_STREAM_NAME,
-				    NULL, 0);
-	if (sname == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	ret = SMB_VFS_NEXT_UNLINK(handle, sname);
-	TALLOC_FREE(sname);
-	if (ret != 0) {
-		DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
-		return map_nt_error_from_unix(errno);
-	}
-
-	return NT_STATUS_OK;
+	return rc;
 }
 
-static NTSTATUS fruit_streaminfo_meta_netatalk(
-	vfs_handle_struct *handle,
-	struct files_struct *fsp,
-	const struct smb_filename *smb_fname,
-	TALLOC_CTX *mem_ctx,
-	unsigned int *pnum_streams,
-	struct stream_struct **pstreams)
+static int fruit_lstat(vfs_handle_struct *handle,
+		       struct smb_filename *smb_fname)
 {
-	struct stream_struct *stream = *pstreams;
-	unsigned int num_streams = *pnum_streams;
-	struct adouble *ad = NULL;
-	bool is_fi_empty;
-	int i;
-	bool ok;
-
-	/*
-	 * Check if there's a AFPINFO_STREAM from the VFS streams
-	 * backend and if yes, remove it from the list
-	 */
-	for (i = 0; i < num_streams; i++) {
-		if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
-			break;
-		}
-	}
+	int rc = -1;
 
-	if (i < num_streams) {
-		DBG_WARNING("Unexpected AFPINFO_STREAM on [%s]\n",
-			    smb_fname_str_dbg(smb_fname));
+	DEBUG(10, ("fruit_lstat called for %s\n",
+		   smb_fname_str_dbg(smb_fname)));
 
-		ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
-				      AFPINFO_STREAM);
-		if (!ok) {
-			return NT_STATUS_INTERNAL_ERROR;
+	if (!is_ntfs_stream_smb_fname(smb_fname)
+	    || is_ntfs_default_stream_smb_fname(smb_fname)) {
+		rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+		if (rc == 0) {
+			update_btime(handle, smb_fname);
 		}
+		return rc;
 	}
 
-	ad = ad_get(talloc_tos(), handle,
-		    smb_fname->base_name, ADOUBLE_META);
-	if (ad == NULL) {
-		return NT_STATUS_OK;
+	if (is_afpinfo_stream(smb_fname)) {
+		rc = fruit_stat_meta(handle, smb_fname, false);
+	} else if (is_afpresource_stream(smb_fname)) {
+		rc = fruit_stat_rsrc(handle, smb_fname, false);
+	} else {
+		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
 	}
 
-	is_fi_empty = ad_empty_finderinfo(ad);
-	TALLOC_FREE(ad);
-
-	if (is_fi_empty) {
-		return NT_STATUS_OK;
+	if (rc == 0) {
+		update_btime(handle, smb_fname);
+		smb_fname->st.st_ex_mode &= ~S_IFMT;
+		smb_fname->st.st_ex_mode |= S_IFREG;
+		smb_fname->st.st_ex_blocks =
+			smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
 	}
+	return rc;
+}
 
-	ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
-			      AFPINFO_STREAM_NAME, AFP_INFO_SIZE,
-			      smb_roundup(handle->conn, AFP_INFO_SIZE));
-	if (!ok) {
-		return NT_STATUS_NO_MEMORY;
-	}
+static int fruit_fstat_meta(vfs_handle_struct *handle,
+			    files_struct *fsp,
+			    SMB_STRUCT_STAT *sbuf)
+{
+	DEBUG(10, ("fruit_fstat_meta called for %s\n",
+		   smb_fname_str_dbg(fsp->base_fsp->fsp_name)));
 
-	/* Remove the Netatalk xattr from the list */
-	ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams,
-			      ":" NETATALK_META_XATTR ":$DATA");
-	if (!ok) {
-		return NT_STATUS_NO_MEMORY;
+	/* Populate the stat struct with info from the base file. */
+	if (fruit_stat_base(handle, fsp->base_fsp->fsp_name, false) == -1) {
+		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 NT_STATUS_OK;
+	return 0;
 }
 
-static NTSTATUS fruit_streaminfo_meta(vfs_handle_struct *handle,
-				      struct files_struct *fsp,
-				      const struct smb_filename *smb_fname,
-				      TALLOC_CTX *mem_ctx,
-				      unsigned int *pnum_streams,
-				      struct stream_struct **pstreams)
+static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp,
+			    SMB_STRUCT_STAT *sbuf)
 {
-	struct fruit_config_data *config = NULL;
-	NTSTATUS status;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
-				return NT_STATUS_INTERNAL_ERROR);
+	struct fruit_config_data *config;
+	struct adouble *ad = (struct adouble *)VFS_FETCH_FSP_EXTENSION(
+		handle, fsp);
 
-	switch (config->meta) {
-	case FRUIT_META_NETATALK:
-		status = fruit_streaminfo_meta_netatalk(handle, fsp, smb_fname,
-							mem_ctx, pnum_streams,
-							pstreams);
-		break;
+	DEBUG(10, ("fruit_fstat_rsrc called for %s\n",
+		   smb_fname_str_dbg(fsp->base_fsp->fsp_name)));
 
-	case FRUIT_META_STREAM:
-		status = fruit_streaminfo_meta_stream(handle, fsp, smb_fname,
-						      mem_ctx, pnum_streams,
-						      pstreams);
-		break;
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-	default:
-		return NT_STATUS_INTERNAL_ERROR;
+	if (config->rsrc == FRUIT_RSRC_STREAM) {
+		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
 	}
 
-	return status;
-}
-
-static NTSTATUS fruit_streaminfo_rsrc_stream(
-	vfs_handle_struct *handle,
-	struct files_struct *fsp,
-	const struct smb_filename *smb_fname,
-	TALLOC_CTX *mem_ctx,
-	unsigned int *pnum_streams,
-	struct stream_struct **pstreams)
-{
-	bool ok;
-
-	ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
-	if (!ok) {
-		DBG_ERR("Filtering resource stream failed\n");
-		return NT_STATUS_INTERNAL_ERROR;
+	/* Populate the stat struct with info from the base file. */
+	if (fruit_stat_base(handle, fsp->base_fsp->fsp_name, false) == -1) {
+		return -1;
 	}
-	return NT_STATUS_OK;
-}
+	*sbuf = fsp->base_fsp->fsp_name->st;
+	sbuf->st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
+	sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
 
-static NTSTATUS fruit_streaminfo_rsrc_xattr(
-	vfs_handle_struct *handle,
-	struct files_struct *fsp,
-	const struct smb_filename *smb_fname,
-	TALLOC_CTX *mem_ctx,
-	unsigned int *pnum_streams,
-	struct stream_struct **pstreams)
-{
-	bool ok;
+	DEBUG(10, ("fruit_fstat_rsrc %s, size: %zd\n",
+		   smb_fname_str_dbg(fsp->fsp_name),
+		   (ssize_t)sbuf->st_ex_size));
 
-	ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
-	if (!ok) {
-		DBG_ERR("Filtering resource stream failed\n");
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-	return NT_STATUS_OK;
+	return 0;
 }
 
-static NTSTATUS fruit_streaminfo_rsrc_adouble(
-	vfs_handle_struct *handle,
-	struct files_struct *fsp,
-	const struct smb_filename *smb_fname,
-	TALLOC_CTX *mem_ctx,
-	unsigned int *pnum_streams,
-	struct stream_struct **pstreams)
+static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
+		       SMB_STRUCT_STAT *sbuf)
 {
-	struct adouble *ad = NULL;
-	bool ok;
-	size_t rlen;
+	int rc;
+	char *name = NULL;
+	char *tmp_base_name = NULL;
+	NTSTATUS status;
+	struct adouble *ad = (struct adouble *)
+		VFS_FETCH_FSP_EXTENSION(handle, fsp);
 
-	ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
-		    ADOUBLE_RSRC);
-	if (ad == NULL) {
-		return NT_STATUS_OK;
-	}
+	DEBUG(10, ("fruit_fstat called for %s\n",
+		   smb_fname_str_dbg(fsp->fsp_name)));
 
-	rlen = ad_getentrylen(ad, ADEID_RFORK);
-	TALLOC_FREE(ad);
+	if (fsp->base_fsp) {
+		tmp_base_name = fsp->base_fsp->fsp_name->base_name;
+		/* fsp_name is not converted with vfs_catia */
+		status = SMB_VFS_TRANSLATE_NAME(
+			handle->conn,
+			fsp->base_fsp->fsp_name->base_name,
+			vfs_translate_to_unix,
+			talloc_tos(), &name);
 
-	if (rlen == 0) {
-		return NT_STATUS_OK;
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+			name = talloc_strdup(talloc_tos(), tmp_base_name);
+			if (name == NULL) {
+				rc = -1;
+				goto exit;
+			}
+		} else if (!NT_STATUS_IS_OK(status)) {
+			errno = map_errno_from_nt_status(status);
+			rc = -1;
+			goto exit;
+		}
+		fsp->base_fsp->fsp_name->base_name = name;
 	}
 
-	ok = add_fruit_stream(mem_ctx, pnum_streams, pstreams,
-			      AFPRESOURCE_STREAM_NAME, rlen,
-			      smb_roundup(handle->conn, rlen));
-	if (!ok) {
-		return NT_STATUS_NO_MEMORY;
+	if (ad == NULL || fsp->base_fsp == NULL) {
+		rc = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+		goto exit;
 	}
 
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS fruit_streaminfo_rsrc(vfs_handle_struct *handle,
-				      struct files_struct *fsp,
-				      const struct smb_filename *smb_fname,
-				      TALLOC_CTX *mem_ctx,
-				      unsigned int *pnum_streams,
-				      struct stream_struct **pstreams)
-{
-	struct fruit_config_data *config = NULL;
-	NTSTATUS status;
-
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
-				return NT_STATUS_INTERNAL_ERROR);
-
-	switch (config->rsrc) {
-	case FRUIT_RSRC_STREAM:
-		status = fruit_streaminfo_rsrc_stream(handle, fsp, smb_fname,
-						      mem_ctx, pnum_streams,
-						      pstreams);
-		break;
+	if (!fruit_fsp_recheck(ad, fsp)) {
+		rc = -1;
+		goto exit;
+	}
 
-	case FRUIT_RSRC_XATTR:
-		status = fruit_streaminfo_rsrc_xattr(handle, fsp, smb_fname,
-						     mem_ctx, pnum_streams,
-						     pstreams);
+	switch (ad->ad_type) {
+	case ADOUBLE_META:
+		rc = fruit_fstat_meta(handle, fsp, sbuf);
 		break;
-
-	case FRUIT_RSRC_ADFILE:
-		status = fruit_streaminfo_rsrc_adouble(handle, fsp, smb_fname,
-						       mem_ctx, pnum_streams,
-						       pstreams);
+	case ADOUBLE_RSRC:
+		rc = fruit_fstat_rsrc(handle, fsp, sbuf);
 		break;
-
 	default:
-		return NT_STATUS_INTERNAL_ERROR;
+		DEBUG(10, ("fruit_fstat %s: bad type\n",
+			   smb_fname_str_dbg(fsp->fsp_name)));
+		rc = -1;
+		goto exit;
 	}
 
-	return status;
+	if (rc == 0) {
+		sbuf->st_ex_mode &= ~S_IFMT;
+		sbuf->st_ex_mode |= S_IFREG;
+		sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
+	}
+
+exit:
+	DEBUG(10, ("fruit_fstat %s, size: %zd\n",
+		   smb_fname_str_dbg(fsp->fsp_name),
+		   (ssize_t)sbuf->st_ex_size));
+	if (tmp_base_name) {
+		fsp->base_fsp->fsp_name->base_name = tmp_base_name;
+	}
+	TALLOC_FREE(name);
+	return rc;
 }
 
 static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
@@ -4637,12 +3188,46 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
 				 struct stream_struct **pstreams)
 {
 	struct fruit_config_data *config = NULL;
+	struct adouble *ad = NULL;
 	NTSTATUS status;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
 				return NT_STATUS_UNSUCCESSFUL);
+	DEBUG(10, ("fruit_streaminfo called for %s\n", smb_fname->base_name));
+
+	if (config->meta == FRUIT_META_NETATALK) {
+		ad = ad_get(talloc_tos(), handle,
+			    smb_fname->base_name, ADOUBLE_META);
+		if (ad && !empty_finderinfo(ad)) {
+			if (!add_fruit_stream(
+				    mem_ctx, pnum_streams, pstreams,
+				    AFPINFO_STREAM_NAME, AFP_INFO_SIZE,
+				    smb_roundup(handle->conn,
+						AFP_INFO_SIZE))) {
+				TALLOC_FREE(ad);
+				return NT_STATUS_NO_MEMORY;
+			}
+		}
+		TALLOC_FREE(ad);
+	}
 
-	DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
+	if (config->rsrc != FRUIT_RSRC_STREAM) {
+		ad = ad_get(talloc_tos(), handle, smb_fname->base_name,
+			    ADOUBLE_RSRC);
+		if (ad && (ad_getentrylen(ad, ADEID_RFORK) > 0)) {
+			if (!add_fruit_stream(
+				    mem_ctx, pnum_streams, pstreams,
+				    AFPRESOURCE_STREAM_NAME,
+				    ad_getentrylen(ad, ADEID_RFORK),
+				    smb_roundup(handle->conn,
+						ad_getentrylen(
+							ad, ADEID_RFORK)))) {
+				TALLOC_FREE(ad);
+				return NT_STATUS_NO_MEMORY;
+			}
+		}
+		TALLOC_FREE(ad);
+	}
 
 	status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname, mem_ctx,
 					 pnum_streams, pstreams);
@@ -4650,16 +3235,13 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
 		return status;
 	}
 
-	status = fruit_streaminfo_meta(handle, fsp, smb_fname,
-				       mem_ctx, pnum_streams, pstreams);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	status = fruit_streaminfo_rsrc(handle, fsp, smb_fname,
-				       mem_ctx, pnum_streams, pstreams);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	if (config->meta == FRUIT_META_NETATALK) {
+		/* Remove the Netatalk xattr from the list */
+		if (!del_fruit_stream(mem_ctx, pnum_streams, pstreams,
+				      ":" NETATALK_META_XATTR ":$DATA")) {
+				TALLOC_FREE(ad);
+				return NT_STATUS_NO_MEMORY;
+		}
 	}
 
 	return NT_STATUS_OK;
@@ -4671,15 +3253,9 @@ static int fruit_ntimes(vfs_handle_struct *handle,
 {
 	int rc = 0;
 	struct adouble *ad = NULL;
-	struct fruit_config_data *config = NULL;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
-				return -1);
-
-	if ((config->meta != FRUIT_META_NETATALK) ||
-	    null_timespec(ft->create_time))
-	{
-		return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
+	if (null_timespec(ft->create_time)) {
+		goto exit;
 	}
 
 	DEBUG(10,("set btime for %s to %s\n", smb_fname_str_dbg(smb_fname),
@@ -4693,7 +3269,7 @@ static int fruit_ntimes(vfs_handle_struct *handle,
 	ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX,
 		   convert_time_t_to_uint32_t(ft->create_time.tv_sec));
 
-	rc = ad_set(ad, smb_fname->base_name);
+	rc = ad_write(ad, smb_fname->base_name);
 
 exit:
 
@@ -4711,120 +3287,79 @@ static int fruit_fallocate(struct vfs_handle_struct *handle,
 			   off_t offset,
 			   off_t len)
 {
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+        struct adouble *ad =
+		(struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
 
-	if (fio == NULL) {
+	if (ad == NULL) {
 		return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
 	}
 
+	if (!fruit_fsp_recheck(ad, fsp)) {
+		return -1;
+	}
+
 	/* Let the pwrite code path handle it. */
 	errno = ENOSYS;
 	return -1;
 }
 
-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);
-	}
-
-	return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
-}
-
-static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle,
-					struct files_struct *fsp,
-					off_t offset)
+static int fruit_ftruncate_meta(struct vfs_handle_struct *handle,
+				struct files_struct *fsp,
+				off_t offset,
+				struct adouble *ad)
 {
-	int rc;
-	struct adouble *ad = NULL;
-	off_t ad_off;
-
-	ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
-	if (ad == NULL) {
-		DBG_DEBUG("ad_get [%s] failed [%s]\n",
-			  fsp_str_dbg(fsp), strerror(errno));
-		return -1;
-	}
-
-	ad_off = ad_getentryoff(ad, ADEID_RFORK);
-
-	rc = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset + ad_off);
-	if (rc != 0) {
-		TALLOC_FREE(ad);
-		return -1;
-	}
+	struct fruit_config_data *config;
 
-	ad_setentrylen(ad, ADEID_RFORK, offset);
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-	rc = ad_fset(ad, fsp);
-	if (rc != 0) {
-		DBG_ERR("ad_fset [%s] failed [%s]\n",
-			fsp_str_dbg(fsp), strerror(errno));
-		TALLOC_FREE(ad);
+	if (offset > 60) {
+		DBG_WARNING("ftruncate %s to %jd",
+			    fsp_str_dbg(fsp), (intmax_t)offset);
+		/* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED  */
+		errno = EOVERFLOW;
 		return -1;
 	}
 
-	TALLOC_FREE(ad);
+	DBG_WARNING("ignoring ftruncate %s to %jd",
+		    fsp_str_dbg(fsp), (intmax_t)offset);
+	/* OS X returns success but does nothing  */
 	return 0;
 }
 
-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);
-}
-
 static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle,
 				struct files_struct *fsp,
-				off_t offset)
+				off_t offset,
+				struct adouble *ad)
 {
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	int ret;
-
-	switch (fio->config->rsrc) {
-	case FRUIT_RSRC_XATTR:
-		ret = fruit_ftruncate_rsrc_xattr(handle, fsp, offset);
-		break;
+	int rc;
+	struct fruit_config_data *config;
 
-	case FRUIT_RSRC_ADFILE:
-		ret = fruit_ftruncate_rsrc_adouble(handle, fsp, offset);
-		break;
+	SMB_VFS_HANDLE_GET_DATA(handle, config,
+				struct fruit_config_data, return -1);
 
-	case FRUIT_RSRC_STREAM:
-		ret = fruit_ftruncate_rsrc_stream(handle, fsp, offset);
-		break;
+	if (config->rsrc == FRUIT_RSRC_XATTR && offset == 0) {
+		return SMB_VFS_FREMOVEXATTR(fsp,
+					    AFPRESOURCE_EA_NETATALK);
+	}
 
-	default:
-		DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc);
+	rc = SMB_VFS_NEXT_FTRUNCATE(
+		handle, fsp,
+		offset + ad_getentryoff(ad, ADEID_RFORK));
+	if (rc != 0) {
 		return -1;
 	}
 
-
-	return ret;
-}
-
-static int fruit_ftruncate_meta(struct vfs_handle_struct *handle,
-				struct files_struct *fsp,
-				off_t offset)
-{
-	if (offset > 60) {
-		DBG_WARNING("ftruncate %s to %jd",
-			    fsp_str_dbg(fsp), (intmax_t)offset);
-		/* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED  */
-		errno = EOVERFLOW;
-		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));
 	}
 
-	/* OS X returns success but does nothing  */
-	DBG_INFO("ignoring ftruncate %s to %jd\n",
-		 fsp_str_dbg(fsp), (intmax_t)offset);
 	return 0;
 }
 
@@ -4832,23 +3367,35 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle,
 			   struct files_struct *fsp,
 			   off_t offset)
 {
-	struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-	int ret;
+	int rc = 0;
+        struct adouble *ad =
+		(struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
 
-	DBG_DEBUG("Path [%s] offset [%zd]\n", fsp_str_dbg(fsp), offset);
+	DBG_DEBUG("fruit_ftruncate called for file %s offset %.0f\n",
+		   fsp_str_dbg(fsp), (double)offset);
 
-	if (fio == NULL) {
+	if (ad == NULL) {
 		return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
 	}
 
-	if (fio->type == ADOUBLE_META) {
-		ret = fruit_ftruncate_meta(handle, fsp, offset);
-	} else {
-		ret = fruit_ftruncate_rsrc(handle, fsp, offset);
+	if (!fruit_fsp_recheck(ad, fsp)) {
+		return -1;
 	}
 
-	DBG_DEBUG("Path [%s] result [%d]\n", fsp_str_dbg(fsp), ret);
-	return ret;
+	switch (ad->ad_type) {
+	case ADOUBLE_META:
+		rc = fruit_ftruncate_meta(handle, fsp, offset, ad);
+		break;
+
+	case ADOUBLE_RSRC:
+		rc = fruit_ftruncate_rsrc(handle, fsp, offset, ad);
+		break;
+
+	default:
+		return -1;
+	}
+
+	return rc;
 }
 
 static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index 2d797f0..d9eb2e1 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -452,18 +452,18 @@ static int streams_xattr_open(vfs_handle_struct *handle,
         hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp,
 			      baseflags, mode);
 
+	TALLOC_FREE(smb_fname_base);
+
         /* It is legit to open a stream on a directory, but the base
          * fd has to be read-only.
          */
         if ((hostfd == -1) && (errno == EISDIR)) {
                 baseflags &= ~O_ACCMODE;
                 baseflags |= O_RDONLY;
-                hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, baseflags,
+                hostfd = SMB_VFS_OPEN(handle->conn, smb_fname, fsp, baseflags,
 				      mode);
         }
 
-	TALLOC_FREE(smb_fname_base);
-
         if (hostfd == -1) {
 		goto fail;
         }
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 0df7df3..d80750e 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -323,7 +323,7 @@ nbt = ["nbt.dgram" ]
 
 libsmbclient = ["libsmbclient"]
 
-vfs = ["vfs.fruit", "vfs.acl_xattr", "vfs.fruit_netatalk"]
+vfs = ["vfs.fruit", "vfs.acl_xattr"]
 
 tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs
 
@@ -404,11 +404,8 @@ for t in tests:
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmpsort -U$USERNAME%$PASSWORD')
         plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
     elif t == "vfs.fruit":
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share --option=torture:share2=vfs_wo_fruit', 'metadata_netatalk')
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream --option=torture:share2=vfs_wo_fruit -U$USERNAME%$PASSWORD', 'metadata_stream')
-        plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_stream_depot --option=torture:share2=vfs_wo_fruit_stream_depot -U$USERNAME%$PASSWORD', 'streams_depot')
-    elif t == "vfs.fruit_netatalk":
         plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share')
+        plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/ad_dc/share')
     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 ca8f430..020bd1f 100644
--- a/source4/torture/vfs/fruit.c
+++ b/source4/torture/vfs/fruit.c
@@ -3527,383 +3527,6 @@ done:
 }
 
 /*
- * This tests that right after creating the AFP_AfpInfo stream,
- * reading from the stream returns an empty, default metadata blob of
- * 60 bytes.
- *
- * NOTE: against OS X SMB server this only works if the read request
- * is compounded with the create that created the stream, is fails
- * otherwise. We don't care...
- */
-static bool test_null_afpinfo(struct torture_context *tctx,
-			      struct smb2_tree *tree)
-{
-	TALLOC_CTX *mem_ctx = talloc_new(tctx);
-	const char *fname = "test_null_afpinfo";
-	const char *sname = "test_null_afpinfo" AFPINFO_STREAM_NAME;
-	NTSTATUS status;
-	bool ret = true;
-	struct smb2_request *req[3];
-	struct smb2_handle handle;
-	struct smb2_create create;
-	struct smb2_read read;
-	AfpInfo *afpinfo = NULL;
-	char *afpinfo_buf = NULL;
-	const char *type_creator = "SMB,OLE!";
-
-	torture_comment(tctx, "Checking create of AfpInfo stream\n");
-
-	smb2_util_unlink(tree, fname);
-
-	ret = torture_setup_file(mem_ctx, tree, fname, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
-
-	ZERO_STRUCT(create);
-	create.in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA;
-	create.in.share_access = FILE_SHARE_READ | FILE_SHARE_DELETE;
-	create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
-	create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
-	create.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
-	create.in.fname = sname;
-
-	smb2_transport_compound_start(tree->session->transport, 2);
-
-	req[0] = smb2_create_send(tree, &create);
-
-	handle.data[0] = UINT64_MAX;
-	handle.data[1] = UINT64_MAX;
-
-	smb2_transport_compound_set_related(tree->session->transport, true);
-
-	ZERO_STRUCT(read);
-	read.in.file.handle = handle;
-	read.in.length = AFP_INFO_SIZE;
-	req[1] = smb2_read_send(tree, &read);
-
-	status = smb2_create_recv(req[0], tree, &create);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create_recv failed");
-
-	handle = create.out.file.handle;
-
-	status = smb2_read_recv(req[1], tree, &read);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_read_recv failed");
-
-	afpinfo = torture_afpinfo_new(mem_ctx);
-	torture_assert_goto(tctx, afpinfo != NULL, ret, done, "torture_afpinfo_new failed");
-
-	memcpy(afpinfo->afpi_FinderInfo, type_creator, 8);
-
-	afpinfo_buf = torture_afpinfo_pack(tctx, afpinfo);
-	torture_assert_goto(tctx, afpinfo_buf != NULL, ret, done, "torture_afpinfo_new failed");
-
-	status = smb2_util_write(tree, handle, afpinfo_buf, 0, AFP_INFO_SIZE);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write failed");
-
-	smb2_util_close(tree, handle);
-
-	ret = check_stream(tree, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM,
-			   0, 60, 16, 8, type_creator);
-	torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed");
-
-done:
-	smb2_util_unlink(tree, fname);
-	talloc_free(mem_ctx);
-	return ret;
-}
-
-static bool test_delete_file_with_rfork(struct torture_context *tctx,
-					struct smb2_tree *tree)
-{
-	const char *fname = "torture_write_rfork_io";
-	const char *rfork_content = "1234567890";
-	NTSTATUS status;
-	bool ret = true;
-
-	smb2_util_unlink(tree, fname);
-
-	torture_comment(tctx, "Test deleting file with resource fork\n");
-
-	ret = torture_setup_file(tctx, tree, fname, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed\n");
-
-	ret = write_stream(tree, __location__, tctx, tctx,
-			   fname, AFPRESOURCE_STREAM_NAME,
-			   10, 10, rfork_content);
-	torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed\n");
-
-	ret = check_stream(tree, __location__, tctx, tctx,
-			   fname, AFPRESOURCE_STREAM_NAME,
-			   0, 20, 10, 10, rfork_content);
-	torture_assert_goto(tctx, ret == true, ret, done, "check_stream failed\n");
-
-	status = smb2_util_unlink(tree, fname);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "check_stream failed\n");
-
-done:
-	return ret;
-}
-
-static bool test_rename_and_read_rsrc(struct torture_context *tctx,
-				      struct smb2_tree *tree)
-{
-	bool ret = true;
-	NTSTATUS status;
-	struct smb2_create create, create2;
-	struct smb2_handle h1, h2;
-	const char *fname = "test_rename_openfile";
-	const char *sname = "test_rename_openfile" AFPRESOURCE_STREAM_NAME;
-	const char *fname_renamed = "test_rename_openfile_renamed";
-	const char *data = "1234567890";
-	union smb_setfileinfo sinfo;
-	struct smb2_read r;
-
-	ret = enable_aapl(tctx, tree);
-	torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
-
-	torture_comment(tctx, "Create file with resource fork\n");
-
-	ret = torture_setup_file(tctx, tree, fname, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
-
-	ret = write_stream(tree, __location__, tctx, tctx,
-			   fname, AFPRESOURCE_STREAM_NAME, 0, 10, data);
-	torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
-
-	torture_comment(tctx, "Open resource fork\n");
-
-	ZERO_STRUCT(create);
-	create.in.desired_access = SEC_FILE_ALL;
-	create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
-	create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
-	create.in.create_disposition = NTCREATEX_DISP_OPEN;
-	create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
-	create.in.fname = sname;
-
-	status = smb2_create(tree, tctx, &create);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
-
-	h1 = create.out.file.handle;
-
-	torture_comment(tctx, "Rename base file\n");
-
-	ZERO_STRUCT(create2);
-	create2.in.desired_access = SEC_FILE_ALL;
-	create2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
-	create2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
-	create2.in.create_disposition = NTCREATEX_DISP_OPEN;
-	create2.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
-	create2.in.fname = fname;
-
-	status = smb2_create(tree, tctx, &create2);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
-
-	h2 = create2.out.file.handle;
-
-	ZERO_STRUCT(sinfo);
-	sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
-	sinfo.rename_information.in.file.handle = h2;
-	sinfo.rename_information.in.overwrite = 0;
-	sinfo.rename_information.in.root_fid = 0;
-	sinfo.rename_information.in.new_name = fname_renamed;
-
-	status = smb2_setinfo_file(tree, &sinfo);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_setinfo_file failed");
-
-	smb2_util_close(tree, h2);
-
-	ZERO_STRUCT(r);
-	r.in.file.handle = h1;
-	r.in.length      = 10;
-	r.in.offset      = 0;
-
-	torture_comment(tctx, "Read resource fork of renamed file\n");
-
-	status = smb2_read(tree, tree, &r);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_read failed");
-
-	smb2_util_close(tree, h1);
-
-	torture_assert_goto(tctx, r.out.data.length == 10, ret, done,
-			    talloc_asprintf(tctx, "smb2_read returned %jd bytes, expected 10\n",
-					    (intmax_t)r.out.data.length));
-
-	torture_assert_goto(tctx, memcmp(r.out.data.data, data, 10) == 0, ret, done,
-			    talloc_asprintf(tctx, "Bad data in stream\n"));
-
-done:
-	smb2_util_unlink(tree, fname);
-	smb2_util_unlink(tree, fname_renamed);
-
-	return ret;
-}
-
-static bool test_readdir_attr_illegal_ntfs(struct torture_context *tctx,
-					   struct smb2_tree *tree)
-{
-	TALLOC_CTX *mem_ctx = talloc_new(tctx);
-	const char *name = "test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */
-	const char *fname = BASEDIR "\\test" "\xef\x80\xa2" "aapl"; /* "test:aapl" */
-	NTSTATUS status;
-	struct smb2_handle testdirh;
-	bool ret = true;
-	struct smb2_create io;
-	AfpInfo *info;
-	const char *type_creator = "SMB,OLE!";
-	struct smb2_find f;
-	unsigned int count;
-	union smb_search_data *d;
-	uint64_t rfork_len;
-	int i;
-
-	smb2_deltree(tree, BASEDIR);
-
-	status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed");
-	smb2_util_close(tree, testdirh);
-
-	torture_comment(tctx, "Enabling AAPL\n");
-
-	ret = enable_aapl(tctx, tree);
-	torture_assert_goto(tctx, ret == true, ret, done, "enable_aapl failed");
-
-	/*
-	 * Now that Requested AAPL extensions are enabled, setup some
-	 * Mac files with metadata and resource fork
-	 */
-
-	torture_comment(tctx, "Preparing file\n");
-
-	ret = torture_setup_file(mem_ctx, tree, fname, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file failed");
-
-	info = torture_afpinfo_new(mem_ctx);
-	torture_assert_not_null_goto(tctx, info, ret, done, "torture_afpinfo_new failed");
-
-	memcpy(info->afpi_FinderInfo, type_creator, 8);
-	ret = torture_write_afpinfo(tree, tctx, mem_ctx, fname, info);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_write_afpinfo failed");
-
-	ret = write_stream(tree, __location__, tctx, mem_ctx,
-			   fname, AFPRESOURCE_STREAM_NAME,
-			   0, 3, "foo");
-	torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
-
-	/*
-	 * Ok, file is prepared, now call smb2/find
-	 */
-
-	torture_comment(tctx, "Issue find\n");
-
-	ZERO_STRUCT(io);
-	io.in.desired_access = SEC_RIGHTS_DIR_READ;
-	io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
-	io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
-	io.in.share_access = (NTCREATEX_SHARE_ACCESS_READ |
-			      NTCREATEX_SHARE_ACCESS_WRITE |
-			      NTCREATEX_SHARE_ACCESS_DELETE);
-	io.in.create_disposition = NTCREATEX_DISP_OPEN;
-	io.in.fname = BASEDIR;
-	status = smb2_create(tree, tctx, &io);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed");
-
-	ZERO_STRUCT(f);
-	f.in.file.handle	= io.out.file.handle;
-	f.in.pattern		= "*";
-	f.in.max_response_size	= 0x1000;
-	f.in.level              = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
-
-	status = smb2_find_level(tree, tree, &f, &count, &d);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_level failed");
-
-	status = smb2_util_close(tree, io.out.file.handle);
-	torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_close failed");
-
-	torture_comment(tctx, "Checking find response with enriched macOS metadata\n");
-
-	for (i = 0; i < count; i++) {
-		const char *found = d[i].id_both_directory_info.name.s;
-
-		if (!strcmp(found, ".") || !strcmp(found, ".."))
-			continue;
-		break;
-	}
-
-	torture_assert_str_equal_goto(tctx,
-				      d[i].id_both_directory_info.name.s, name,
-				      ret, done, "bad name");
-
-	rfork_len = BVAL(d[i].id_both_directory_info.short_name_buf, 0);
-	torture_assert_int_equal_goto(tctx, rfork_len, 3, ret, done, "bad resource fork length");
-
-	torture_assert_mem_equal_goto(tctx, type_creator,
-				      d[i].id_both_directory_info.short_name_buf + 8,
-				      8, ret, done, "Bad FinderInfo");
-done:
-	smb2_util_unlink(tree, fname);
-	smb2_deltree(tree, BASEDIR);
-	talloc_free(mem_ctx);
-	return ret;
-}
-
-static bool test_invalid_afpinfo(struct torture_context *tctx,
-				 struct smb2_tree *tree1,
-				 struct smb2_tree *tree2)
-{
-	const char *fname = "filtest_invalid_afpinfo";
-	const char *sname = "filtest_invalid_afpinfo" AFPINFO_STREAM_NAME;
-	struct smb2_create create;
-	const char *streams_basic[] = {
-		"::$DATA"
-	};
-	const char *streams_afpinfo[] = {
-		"::$DATA",
-		AFPINFO_STREAM
-	};
-	NTSTATUS status;
-	bool ret = true;
-
-	if (tree2 == NULL) {
-		torture_skip_goto(tctx, done, "need second share without fruit\n");
-	}
-
-	torture_comment(tctx, "Testing invalid AFP_AfpInfo stream\n");
-
-	ret = torture_setup_file(tctx, tree2, fname, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "torture_setup_file");
-
-	ret = write_stream(tree2, __location__, tctx, tctx,
-			   fname, AFPINFO_STREAM_NAME,
-			   0, 3, "foo");
-	torture_assert_goto(tctx, ret == true, ret, done, "write_stream failed");
-
-	ret = check_stream_list(tree2, tctx, fname, 2, streams_afpinfo, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
-
-	torture_comment(tctx, "Listing streams, bad AFPINFO stream must not be present\n");
-
-	ret = check_stream_list(tree1, tctx, fname, 1, streams_basic, false);
-	torture_assert_goto(tctx, ret == true, ret, done, "Bad streams");
-
-	torture_comment(tctx, "Try to open AFPINFO stream, must fail\n");
-
-	ZERO_STRUCT(create);
-	create.in.desired_access = SEC_FILE_ALL;
-	create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
-	create.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
-	create.in.create_disposition = NTCREATEX_DISP_OPEN;
-	create.in.impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
-	create.in.fname = sname;
-
-	status = smb2_create(tree1, tctx, &create);
-	torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
-					   ret, done, "Stream still around?");
-
-done:
-	smb2_util_unlink(tree1, fname);
-	return ret;
-}
-
-/*
  * Note: This test depends on "vfs objects = catia fruit streams_xattr".  For
  * some tests torture must be run on the host it tests and takes an additional
  * argument with the local path to the share:
@@ -3919,9 +3542,11 @@ struct torture_suite *torture_vfs_fruit(void)
 	suite->description = talloc_strdup(suite, "vfs_fruit tests");
 
 	torture_suite_add_1smb2_test(suite, "copyfile", test_copyfile);
+	torture_suite_add_1smb2_test(suite, "read netatalk metadata", test_read_netatalk_metadata);
 	torture_suite_add_1smb2_test(suite, "read metadata", test_read_afpinfo);
 	torture_suite_add_1smb2_test(suite, "write metadata", test_write_atalk_metadata);
 	torture_suite_add_1smb2_test(suite, "resource fork IO", test_write_atalk_rfork_io);
+	torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion", test_adouble_conversion);
 	torture_suite_add_1smb2_test(suite, "SMB2/CREATE context AAPL", test_aapl);
 	torture_suite_add_1smb2_test(suite, "stream names", test_stream_names);
 	torture_suite_add_1smb2_test(suite, "truncate resource fork to 0 bytes", test_rfork_truncate);
@@ -3935,25 +3560,6 @@ struct torture_suite *torture_vfs_fruit(void)
 	torture_suite_add_1smb2_test(suite, "create delete-on-close AFP_AfpResource", test_create_delete_on_close_resource);
 	torture_suite_add_1smb2_test(suite, "setinfo delete-on-close AFP_AfpResource", test_setinfo_delete_on_close_resource);
 	torture_suite_add_1smb2_test(suite, "setinfo eof AFP_AfpResource", test_setinfo_eof_resource);
-	torture_suite_add_1smb2_test(suite, "null afpinfo", test_null_afpinfo);
-	torture_suite_add_1smb2_test(suite, "delete", test_delete_file_with_rfork);
-	torture_suite_add_1smb2_test(suite, "read open rsrc after rename", test_rename_and_read_rsrc);
-	torture_suite_add_1smb2_test(suite, "readdir_attr with names with illegal ntfs characters", test_readdir_attr_illegal_ntfs);
-
-	torture_suite_add_2ns_smb2_test(suite, "invalid AFP_AfpInfo", test_invalid_afpinfo);
-
-	return suite;
-}
-
-struct torture_suite *torture_vfs_fruit_netatalk(void)
-{
-	struct torture_suite *suite = torture_suite_create(
-		talloc_autofree_context(), "fruit_netatalk");
-
-	suite->description = talloc_strdup(suite, "vfs_fruit tests for Netatalk interop that require fruit:metadata=netatalk");
-
-	torture_suite_add_1smb2_test(suite, "read netatalk metadata", test_read_netatalk_metadata);
-	torture_suite_add_1smb2_test(suite, "OS X AppleDouble file conversion", test_adouble_conversion);
 
 	return suite;
 }
diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c
index a4f8125..7f805f4 100644
--- a/source4/torture/vfs/vfs.c
+++ b/source4/torture/vfs/vfs.c
@@ -38,44 +38,42 @@ static bool wrap_2ns_smb2_test(struct torture_context *torture_ctx,
 			       struct torture_test *test)
 {
 	bool (*fn) (struct torture_context *, struct smb2_tree *, struct smb2_tree *);
-	bool ok;
+	bool ret = false;
 
-	struct smb2_tree *tree1 = NULL;
-	struct smb2_tree *tree2 = NULL;
+	struct smb2_tree *tree1;
+	struct smb2_tree *tree2;
 	TALLOC_CTX *mem_ctx = talloc_new(torture_ctx);
 
-	if (!torture_smb2_connection(torture_ctx, &tree1)) {
+	if (!torture_smb2_con_sopt(torture_ctx, "share1", &tree1)) {
 		torture_fail(torture_ctx,
-			    "Establishing SMB2 connection failed\n");
-		return false;
+		    "Establishing SMB2 connection failed\n");
+		goto done;
 	}
 
-	/*
-	 * This is a trick:
-	 * The test might close the connection. If we steal the tree context
-	 * before that and free the parent instead of tree directly, we avoid
-	 * a double free error.
-	 */
 	talloc_steal(mem_ctx, tree1);
 
-	ok = torture_smb2_con_sopt(torture_ctx, "share2", &tree2);
-	if (ok) {
-		talloc_steal(mem_ctx, tree2);
+	if (!torture_smb2_con_sopt(torture_ctx, "share2", &tree2)) {
+		torture_fail(torture_ctx,
+		    "Establishing SMB2 connection failed\n");
+		goto done;
 	}
 
+	talloc_steal(mem_ctx, tree2);
+
 	fn = test->fn;
 
-	ok = fn(torture_ctx, tree1, tree2);
+	ret = fn(torture_ctx, tree1, tree2);
 
+done:
 	/* the test may already have closed some of the connections */
 	talloc_free(mem_ctx);
 
-	return ok;
+	return ret;
 }
 
 /*
- * Run a test with 2 connected trees, the default share and another
- * taken from option strings "torture:share2"
+ * Run a test with 2 connected trees, Share names to connect are taken
+ * from option strings "torture:share1" and "torture:share2"
  */
 struct torture_test *torture_suite_add_2ns_smb2_test(struct torture_suite *suite,
 						     const char *name,
@@ -109,7 +107,6 @@ NTSTATUS torture_vfs_init(void)
 	suite->description = talloc_strdup(suite, "VFS modules tests");
 
 	torture_suite_add_suite(suite, torture_vfs_fruit());
-	torture_suite_add_suite(suite, torture_vfs_fruit_netatalk());
 	torture_suite_add_suite(suite, torture_acl_xattr());
 
 	torture_register_suite(suite);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git




More information about the Pkg-samba-maint mailing list