From b3db000f4159e2b33282f574f842af9d6ed455dd Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 15 Nov 2016 13:07:12 +0100 Subject: [PATCH 01/60] selftest: don't run vfs_fruit tests against ad_dc env This is just redundant and didn't add test coverage. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 5e612352225e0296e3f91c8db2adcca4f098e514) --- source3/selftest/tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 07e94ed..4ca064a 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -413,7 +413,6 @@ for t in tests: 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') - 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)") -- 2.9.3 From 6eab30079664b7a64f38d9fcc8cd49525ead57a2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 16 Nov 2016 11:24:59 +0100 Subject: [PATCH 02/60] s3/includes: add FinderInfo offset define to MacExtensions.h BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 73a0768865a1f5e74d50e601641cbac5340f9e2d) --- source3/include/MacExtensions.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source3/include/MacExtensions.h b/source3/include/MacExtensions.h index 23dcde9..e17d39b 100644 --- a/source3/include/MacExtensions.h +++ b/source3/include/MacExtensions.h @@ -51,6 +51,9 @@ #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 -- 2.9.3 From 0b63d4c20437c690c57e9b210a9b2d57ea9e451e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 1 Dec 2016 11:17:48 +0100 Subject: [PATCH 03/60] vfs_streams_xattr: call SMB_VFS_OPEN with smb_fname_base In case an SMB_VFS_OPEN() on a stream basename fails with EISDIR, we retry the open as O_RDONLY. The retry should be done with the smb_fname_base as well. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 8035754c28c1a469de4fac77247ef7e5a1d8b463) --- source3/modules/vfs_streams_xattr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index 6a7f3e6..e193d35 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, fsp, baseflags, + hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, baseflags, mode); } + TALLOC_FREE(smb_fname_base); + if (hostfd == -1) { goto fail; } -- 2.9.3 From 9ad4cd293e428c6b5efaf89728f1c0ef0425be7e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 8 Feb 2017 19:16:21 +0100 Subject: [PATCH 04/60] vfs_streams_xattr: use SMB_VFS_NEXT_OPEN and CLOSE Using the SMB_VFS_OPEN leads to a recursion in the VFS that is hard to follow and debug. It's called twice for the same fsp with two different smb_fname's which makes it at least hard to debug, it may even be an invalid usage. Changing this here to use the NEXT function instead should have no change in behaviour otherwise. Bug: https://bugzilla.samba.org/show_bug.cgi?id=12565 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 4e2c7d0ec45adf5992446e3e05c90dd40c2fd75b) --- source3/modules/vfs_streams_xattr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index e193d35..6692636 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -449,8 +449,8 @@ static int streams_xattr_open(vfs_handle_struct *handle, baseflags &= ~O_EXCL; baseflags &= ~O_CREAT; - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, - baseflags, mode); + hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, + baseflags, mode); /* It is legit to open a stream on a directory, but the base * fd has to be read-only. @@ -458,8 +458,8 @@ static int streams_xattr_open(vfs_handle_struct *handle, if ((hostfd == -1) && (errno == EISDIR)) { baseflags &= ~O_ACCMODE; baseflags |= O_RDONLY; - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, baseflags, - mode); + hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, baseflags, + mode); } TALLOC_FREE(smb_fname_base); @@ -547,7 +547,7 @@ static int streams_xattr_open(vfs_handle_struct *handle, * we don't have a full fsp yet */ fsp->fh->fd = hostfd; - SMB_VFS_CLOSE(fsp); + SMB_VFS_NEXT_CLOSE(handle, fsp); } return -1; -- 2.9.3 From 1cb5e3aad226334e4c731ed21fce9558714cfe00 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2016 15:00:58 +0100 Subject: [PATCH 05/60] vfs_catia: run translation on all handle based VFS functions Also run translation of fsp->fsp_name and optionally fsp->base_fsp->fsp_name if set for all handle based VFS functions. This is necessary because some modules might use the path for something in the handle based VFS ops. An existing example is vfs_fruit. A later commit will remove the translation that was done there because catia didn't before this commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Ralph Boehme Signed-off-by: Stefan Metzmacher Reviewed-by: Uri Simchoni (cherry picked from commit af3b4ea4744ab2b67b4221cd6118b6cd2774660f) --- source3/modules/vfs_catia.c | 1257 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1221 insertions(+), 36 deletions(-) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index f4c77d9..eb2e49e 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -4,13 +4,13 @@ * Implement a fixed mapping of forbidden NT characters in filenames that are * used a lot by the CAD package Catia. * - * Yes, this a BAD BAD UGLY INCOMPLETE hack, but it helps quite some people - * out there. Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden - * under Windows... + * Catia V4 on AIX uses characters like "<*$ a *lot*, all forbidden under + * Windows... * * Copyright (C) Volker Lendecke, 2005 * Copyright (C) Aravind Srinivasan, 2009 * Copyright (C) Guenter Kukkukk, 2013 + * Copyright (C) Ralph Boehme, 2017 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,8 @@ #include "includes.h" #include "smbd/smbd.h" +#include "lib/util/tevent_unix.h" +#include "lib/util/tevent_ntstatus.h" static int vfs_catia_debug_level = DBGC_VFS; @@ -52,6 +54,15 @@ struct share_mapping_entry { struct char_mappings **mappings; }; +struct catia_cache { + bool is_fsp_ext; + const struct catia_cache * const *busy; + char *orig_fname; + char *fname; + char *orig_base_fname; + char *base_fname; +}; + struct share_mapping_entry *srt_head = NULL; static bool build_table(struct char_mappings **cmaps, int value) @@ -353,30 +364,305 @@ static NTSTATUS catia_translate_name(struct vfs_handle_struct *handle, return ret; } +#define CATIA_DEBUG_CC(lvl, cc, fsp) \ + catia_debug_cc((lvl), (cc), (fsp), __location__); + +static void catia_debug_cc(int lvl, + struct catia_cache *cc, + files_struct *fsp, + const char *location) +{ + DEBUG(lvl, ("%s: cc [0x%p] cc->busy [0x%p] " + "is_fsp_ext [%s] " + "fsp [0x%p] fsp name [%s] " + "orig_fname [%s] " + "fname [%s] " + "orig_base_fname [%s] " + "base_fname [%s]\n", + location, + cc, cc->busy, + cc->is_fsp_ext ? "yes" : "no", + fsp, fsp_str_dbg(fsp), + cc->orig_fname, cc->fname, + cc->orig_base_fname, cc->base_fname)); +} + +static void catia_free_cc(struct catia_cache **_cc, + vfs_handle_struct *handle, + files_struct *fsp) +{ + struct catia_cache *cc = *_cc; + + if (cc->is_fsp_ext) { + VFS_REMOVE_FSP_EXTENSION(handle, fsp); + cc = NULL; + } else { + TALLOC_FREE(cc); + } + + *_cc = NULL; +} + +static struct catia_cache *catia_validate_and_apply_cc( + vfs_handle_struct *handle, + files_struct *fsp, + const struct catia_cache * const *busy, + bool *make_tmp_cache) +{ + struct catia_cache *cc = NULL; + + *make_tmp_cache = false; + + cc = (struct catia_cache *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + if (cc == NULL) { + return NULL; + } + + if (cc->busy != NULL) { + if (cc->busy == busy) { + /* This should never happen */ + CATIA_DEBUG_CC(0, cc, fsp); + smb_panic(__location__); + } + + /* + * Recursion. Validate names, the names in the fsp's should be + * the translated names we had set. + */ + + if ((cc->fname != fsp->fsp_name->base_name) + || + ((fsp->base_fsp != NULL) && + (cc->base_fname != fsp->base_fsp->fsp_name->base_name))) + { + CATIA_DEBUG_CC(10, cc, fsp); + + /* + * Names changed. Setting don't expose the cache on the + * fsp and ask the caller to create a temporary cache. + */ + *make_tmp_cache = true; + return NULL; + } + + /* + * Ok, a validated cache while in a recursion, just let the + * caller detect that cc->busy is != busy and there's + * nothing else to do. + */ + CATIA_DEBUG_CC(10, cc, fsp); + return cc; + } + + /* Not in a recursion */ + + if ((cc->orig_fname != fsp->fsp_name->base_name) + || + ((fsp->base_fsp != NULL) && + (cc->orig_base_fname != fsp->base_fsp->fsp_name->base_name))) + { + /* + * fsp names changed, this can happen in an rename op. + * Trigger recreation as a full fledged fsp extension. + */ + + CATIA_DEBUG_CC(10, cc, fsp); + catia_free_cc(&cc, handle, fsp); + return NULL; + } + + + /* + * Ok, we found a valid cache entry, no recursion. Just set translated + * names from the cache and mark the cc as busy. + */ + fsp->fsp_name->base_name = cc->fname; + if (fsp->base_fsp != NULL) { + fsp->base_fsp->fsp_name->base_name = cc->base_fname; + } + + cc->busy = busy; + CATIA_DEBUG_CC(10, cc, fsp); + return cc; +} + +#define CATIA_FETCH_FSP_PRE_NEXT(mem_ctx, handle, fsp, _cc) \ + catia_fetch_fsp_pre_next((mem_ctx), (handle), (fsp), (_cc), __func__); + +static int catia_fetch_fsp_pre_next(TALLOC_CTX *mem_ctx, + vfs_handle_struct *handle, + files_struct *fsp, + struct catia_cache **_cc, + const char *function) +{ + const struct catia_cache * const *busy = + (const struct catia_cache * const *)_cc; + struct catia_cache *cc = NULL; + NTSTATUS status; + bool make_tmp_cache = false; + + *_cc = NULL; + + DBG_DEBUG("Called from [%s]\n", function); + + cc = catia_validate_and_apply_cc(handle, + fsp, + busy, + &make_tmp_cache); + if (cc != NULL) { + if (cc->busy != busy) { + return 0; + } + *_cc = cc; + return 0; + } + + if (!make_tmp_cache) { + cc = (struct catia_cache *)VFS_ADD_FSP_EXTENSION( + handle, fsp, struct catia_cache, NULL); + if (cc == NULL) { + return -1; + } + *cc = (struct catia_cache) { + .is_fsp_ext = true, + }; + + mem_ctx = VFS_MEMCTX_FSP_EXTENSION(handle, fsp); + if (mem_ctx == NULL) { + DBG_ERR("VFS_MEMCTX_FSP_EXTENSION failed\n"); + catia_free_cc(&cc, handle, fsp); + return -1; + } + } else { + cc = talloc_zero(mem_ctx, struct catia_cache); + if (cc == NULL) { + return -1; + } + mem_ctx = cc; + } + + + status = catia_string_replace_allocate(handle->conn, + fsp->fsp_name->base_name, + &cc->fname, + vfs_translate_to_unix); + if (!NT_STATUS_IS_OK(status)) { + catia_free_cc(&cc, handle, fsp); + errno = map_errno_from_nt_status(status); + return -1; + } + talloc_steal(mem_ctx, cc->fname); + + if (fsp->base_fsp != NULL) { + status = catia_string_replace_allocate( + handle->conn, + fsp->base_fsp->fsp_name->base_name, + &cc->base_fname, + vfs_translate_to_unix); + if (!NT_STATUS_IS_OK(status)) { + catia_free_cc(&cc, handle, fsp); + errno = map_errno_from_nt_status(status); + return -1; + } + talloc_steal(mem_ctx, cc->base_fname); + } + + cc->orig_fname = fsp->fsp_name->base_name; + fsp->fsp_name->base_name = cc->fname; + + if (fsp->base_fsp != NULL) { + cc->orig_base_fname = fsp->base_fsp->fsp_name->base_name; + fsp->base_fsp->fsp_name->base_name = cc->base_fname; + } + + cc->busy = busy; + CATIA_DEBUG_CC(10, cc, fsp); + + *_cc = cc; + + return 0; +} + +#define CATIA_FETCH_FSP_POST_NEXT(_cc, fsp) do { \ + int saved_errno = errno; \ + catia_fetch_fsp_post_next((_cc), (fsp), __func__); \ + errno = saved_errno; \ +} while(0) + +static void catia_fetch_fsp_post_next(struct catia_cache **_cc, + files_struct *fsp, + const char *function) +{ + const struct catia_cache * const *busy = + (const struct catia_cache * const *)_cc; + struct catia_cache *cc = *_cc; + + DBG_DEBUG("Called from [%s]\n", function); + + if (cc == NULL) { + /* + * This can happen when recursing in the VFS on the fsp when the + * pre_next func noticed the recursion and set out cc pointer to + * NULL. + */ + return; + } + + if (cc->busy != busy) { + CATIA_DEBUG_CC(0, cc, fsp); + smb_panic(__location__); + return; + } + + cc->busy = NULL; + *_cc = NULL; + + fsp->fsp_name->base_name = cc->orig_fname; + if (fsp->base_fsp != NULL) { + fsp->base_fsp->fsp_name->base_name = cc->orig_base_fname; + } + + CATIA_DEBUG_CC(10, cc, fsp); + + if (!cc->is_fsp_ext) { + TALLOC_FREE(cc); + } + + return; +} + static int catia_open(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) { - char *name_mapped = NULL; - char *tmp_base_name; - int ret; + struct catia_cache *cc = NULL; + char *orig_smb_fname = smb_fname->base_name; + char *mapped_smb_fname = NULL; NTSTATUS status; + int ret; - tmp_base_name = smb_fname->base_name; status = catia_string_replace_allocate(handle->conn, - smb_fname->base_name, - &name_mapped, vfs_translate_to_unix); + smb_fname->base_name, + &mapped_smb_fname, + vfs_translate_to_unix); if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); return -1; } - smb_fname->base_name = name_mapped; + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + TALLOC_FREE(mapped_smb_fname); + return ret; + } + + smb_fname->base_name = mapped_smb_fname; ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); - smb_fname->base_name = tmp_base_name; - TALLOC_FREE(name_mapped); + smb_fname->base_name = orig_smb_fname; + + TALLOC_FREE(mapped_smb_fname); + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); return ret; } @@ -1114,33 +1400,932 @@ catia_setxattr(vfs_handle_struct *handle, const char *path, return ret; } -static struct vfs_fn_pointers vfs_catia_fns = { - .mkdir_fn = catia_mkdir, - .rmdir_fn = catia_rmdir, - .opendir_fn = catia_opendir, - .open_fn = catia_open, - .rename_fn = catia_rename, - .stat_fn = catia_stat, - .lstat_fn = catia_lstat, - .unlink_fn = catia_unlink, - .chown_fn = catia_chown, - .lchown_fn = catia_lchown, - .chmod_fn = catia_chmod, - .chdir_fn = catia_chdir, - .ntimes_fn = catia_ntimes, - .realpath_fn = catia_realpath, - .chflags_fn = catia_chflags, - .streaminfo_fn = catia_streaminfo, - .translate_name_fn = catia_translate_name, - .get_nt_acl_fn = catia_get_nt_acl, - .chmod_acl_fn = catia_chmod_acl, - .sys_acl_get_file_fn = catia_sys_acl_get_file, - .sys_acl_set_file_fn = catia_sys_acl_set_file, - .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file, +static int catia_fstat(vfs_handle_struct *handle, + files_struct *fsp, + SMB_STRUCT_STAT *sbuf) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static ssize_t catia_pread(vfs_handle_struct *handle, + files_struct *fsp, void *data, + size_t n, off_t offset) +{ + struct catia_cache *cc = NULL; + ssize_t result; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static ssize_t catia_pwrite(vfs_handle_struct *handle, + files_struct *fsp, const void *data, + size_t n, off_t offset) +{ + struct catia_cache *cc = NULL; + ssize_t result; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static int catia_ftruncate(struct vfs_handle_struct *handle, + struct files_struct *fsp, + off_t offset) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static int catia_fallocate(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t mode, + off_t offset, + off_t len) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + 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 *mapped_xattr_name = NULL; + NTSTATUS status; + ssize_t result; + + status = catia_string_replace_allocate(handle->conn, + name, &mapped_xattr_name, + vfs_translate_to_unix); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, mapped_xattr_name, + value, size); + + TALLOC_FREE(mapped_xattr_name); + + return result; +} + +static ssize_t catia_flistxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + char *list, + size_t size) +{ + struct catia_cache *cc = NULL; + ssize_t result; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static int catia_fremovexattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name) +{ + char *mapped_name = NULL; + NTSTATUS status; + int ret; + + status = catia_string_replace_allocate(handle->conn, + name, &mapped_name, vfs_translate_to_unix); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, mapped_name); + + TALLOC_FREE(mapped_name); + + 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 *mapped_xattr_name = NULL; + NTSTATUS status; + int ret; + + status = catia_string_replace_allocate( + handle->conn, name, &mapped_xattr_name, vfs_translate_to_unix); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, mapped_xattr_name, + value, size, flags); + + TALLOC_FREE(mapped_xattr_name); + + return ret; +} + +static SMB_ACL_T catia_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + TALLOC_CTX *mem_ctx) +{ + struct catia_cache *cc = NULL; + struct smb_acl_t *result = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return NULL; + } + + result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, mem_ctx); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + 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) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx, + blob_description, blob); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static int catia_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + SMB_ACL_T theacl) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static int catia_fchmod_acl(vfs_handle_struct *handle, + files_struct *fsp, + mode_t mode) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + 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) +{ + struct catia_cache *cc = NULL; + NTSTATUS status; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, + mem_ctx, ppdesc); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + 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) +{ + struct catia_cache *cc = NULL; + NTSTATUS status; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return status; +} + +static NTSTATUS catia_fset_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t dosmode) +{ + struct catia_cache *cc = NULL; + NTSTATUS status; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return status; +} + +static NTSTATUS catia_fget_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t *dosmode) +{ + struct catia_cache *cc = NULL; + NTSTATUS status; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + status = SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return status; +} + +static int catia_fchown(vfs_handle_struct *handle, + files_struct *fsp, + uid_t uid, + gid_t gid) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static int catia_fchmod(vfs_handle_struct *handle, + files_struct *fsp, + mode_t mode) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return ret; + } + + ret = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +struct catia_pread_state { + ssize_t ret; + struct vfs_aio_state vfs_aio_state; + struct files_struct *fsp; + struct catia_cache *cc; +}; + +static void catia_pread_done(struct tevent_req *subreq); + +static struct tevent_req *catia_pread_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + void *data, + size_t n, + off_t offset) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct catia_pread_state *state = NULL; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct catia_pread_state); + if (req == NULL) { + return NULL; + } + state->fsp = fsp; + + ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc); + if (ret != 0) { + tevent_req_error(req, errno); + return tevent_req_post(req, ev); + } + + subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data, + n, offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, catia_pread_done, req); + + return req; +} + +static void catia_pread_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct catia_pread_state *state = tevent_req_data( + req, struct catia_pread_state); + + state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + + CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp); + + tevent_req_done(req); +} + +static ssize_t catia_pread_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct catia_pread_state *state = tevent_req_data( + req, struct catia_pread_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +struct catia_pwrite_state { + ssize_t ret; + struct vfs_aio_state vfs_aio_state; + struct files_struct *fsp; + struct catia_cache *cc; +}; + +static void catia_pwrite_done(struct tevent_req *subreq); + +static struct tevent_req *catia_pwrite_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp, + const void *data, + size_t n, + off_t offset) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct catia_pwrite_state *state = NULL; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct catia_pwrite_state); + if (req == NULL) { + return NULL; + } + state->fsp = fsp; + + ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc); + if (ret != 0) { + tevent_req_error(req, errno); + return tevent_req_post(req, ev); + } + + subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data, + n, offset); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, catia_pwrite_done, req); + + return req; +} + +static void catia_pwrite_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct catia_pwrite_state *state = tevent_req_data( + req, struct catia_pwrite_state); + + state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + + CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp); + + tevent_req_done(req); +} + +static ssize_t catia_pwrite_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct catia_pwrite_state *state = tevent_req_data( + req, struct catia_pwrite_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +static off_t catia_lseek(vfs_handle_struct *handle, + files_struct *fsp, + off_t offset, + int whence) +{ + struct catia_cache *cc = NULL; + ssize_t result; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static int catia_fsync(vfs_handle_struct *handle, files_struct *fsp) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ret = SMB_VFS_NEXT_FSYNC(handle, fsp); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +struct catia_fsync_state { + int ret; + struct vfs_aio_state vfs_aio_state; + struct files_struct *fsp; + struct catia_cache *cc; +}; + +static void catia_fsync_done(struct tevent_req *subreq); + +static struct tevent_req *catia_fsync_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *fsp) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct catia_fsync_state *state = NULL; + int ret; + + req = tevent_req_create(mem_ctx, &state, + struct catia_fsync_state); + if (req == NULL) { + return NULL; + } + state->fsp = fsp; + + ret = CATIA_FETCH_FSP_PRE_NEXT(state, handle, fsp, &state->cc); + if (ret != 0) { + tevent_req_error(req, errno); + return tevent_req_post(req, ev); + } + + subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, catia_fsync_done, req); + + return req; +} + +static void catia_fsync_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct catia_fsync_state *state = tevent_req_data( + req, struct catia_fsync_state); + + state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state); + TALLOC_FREE(subreq); + + CATIA_FETCH_FSP_POST_NEXT(&state->cc, state->fsp); + + tevent_req_done(req); +} + +static int catia_fsync_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct catia_fsync_state *state = tevent_req_data( + req, struct catia_fsync_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} + +static bool catia_lock(vfs_handle_struct *handle, + files_struct *fsp, + int op, + off_t offset, + off_t count, + int type) +{ + struct catia_cache *cc = NULL; + bool ok; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ok = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ok; +} + +static int catia_kernel_flock(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t share_mode, + uint32_t access_mask) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ret = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode, access_mask); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static int catia_linux_setlease(vfs_handle_struct *handle, + files_struct *fsp, + int leasetype) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ret = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ret; +} + +static bool catia_getlock(vfs_handle_struct *handle, + files_struct *fsp, + off_t *poffset, + off_t *pcount, + int *ptype, + pid_t *ppid) +{ + struct catia_cache *cc = NULL; + int ret; + bool ok; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ok = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ok; +} + +static bool catia_strict_lock(struct vfs_handle_struct *handle, + struct files_struct *fsp, + struct lock_struct *plock) +{ + struct catia_cache *cc = NULL; + int ret; + bool ok; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return -1; + } + + ok = SMB_VFS_NEXT_STRICT_LOCK(handle, fsp, plock); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return ok; +} + +static void catia_strict_unlock(struct vfs_handle_struct *handle, + struct files_struct *fsp, + struct lock_struct *plock) +{ + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + smb_panic("CATIA_FETCH_FSP_PRE_NEXT failed\n"); + } + + SMB_VFS_NEXT_STRICT_UNLOCK(handle, fsp, plock); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); +} + +static NTSTATUS catia_fsctl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + TALLOC_CTX *ctx, + uint32_t function, + uint16_t req_flags, + const uint8_t *_in_data, + uint32_t in_len, + uint8_t **_out_data, + uint32_t max_out_len, + uint32_t *out_len) +{ + NTSTATUS result; + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + result = SMB_VFS_NEXT_FSCTL(handle, + fsp, + ctx, + function, + req_flags, + _in_data, + in_len, + _out_data, + max_out_len, + out_len); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static NTSTATUS catia_get_compression(vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + struct smb_filename *smb_fname, + uint16_t *_compression_fmt) +{ + NTSTATUS result; + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + result = SMB_VFS_NEXT_GET_COMPRESSION(handle, mem_ctx, fsp, smb_fname, + _compression_fmt); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static NTSTATUS catia_set_compression(vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct files_struct *fsp, + uint16_t compression_fmt) +{ + NTSTATUS result; + struct catia_cache *cc = NULL; + int ret; + + ret = CATIA_FETCH_FSP_PRE_NEXT(talloc_tos(), handle, fsp, &cc); + if (ret != 0) { + return map_nt_error_from_unix(errno); + } + + result = SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp, + compression_fmt); + + CATIA_FETCH_FSP_POST_NEXT(&cc, fsp); + + return result; +} + +static struct vfs_fn_pointers vfs_catia_fns = { + /* Directory operations */ + .mkdir_fn = catia_mkdir, + .rmdir_fn = catia_rmdir, + .opendir_fn = catia_opendir, + + /* File operations */ + .open_fn = catia_open, + .pread_fn = catia_pread, + .pread_send_fn = catia_pread_send, + .pread_recv_fn = catia_pread_recv, + .pwrite_fn = catia_pwrite, + .pwrite_send_fn = catia_pwrite_send, + .pwrite_recv_fn = catia_pwrite_recv, + .lseek_fn = catia_lseek, + .rename_fn = catia_rename, + .fsync_fn = catia_fsync, + .fsync_send_fn = catia_fsync_send, + .fsync_recv_fn = catia_fsync_recv, + .stat_fn = catia_stat, + .fstat_fn = catia_fstat, + .lstat_fn = catia_lstat, + .unlink_fn = catia_unlink, + .chmod_fn = catia_chmod, + .fchmod_fn = catia_fchmod, + .chown_fn = catia_chown, + .fchown_fn = catia_fchown, + .lchown_fn = catia_lchown, + .chdir_fn = catia_chdir, + .ntimes_fn = catia_ntimes, + .ftruncate_fn = catia_ftruncate, + .fallocate_fn = catia_fallocate, + .lock_fn = catia_lock, + .kernel_flock_fn = catia_kernel_flock, + .linux_setlease_fn = catia_linux_setlease, + .getlock_fn = catia_getlock, + .realpath_fn = catia_realpath, + .chflags_fn = catia_chflags, + .streaminfo_fn = catia_streaminfo, + .strict_lock_fn = catia_strict_lock, + .strict_unlock_fn = catia_strict_unlock, + .translate_name_fn = catia_translate_name, + .fsctl_fn = catia_fsctl, + .fset_dos_attributes_fn = catia_fset_dos_attributes, + .fget_dos_attributes_fn = catia_fget_dos_attributes, + .get_compression_fn = catia_get_compression, + .set_compression_fn = catia_set_compression, + + /* NT ACL operations. */ + .get_nt_acl_fn = catia_get_nt_acl, + .fget_nt_acl_fn = catia_fget_nt_acl, + .fset_nt_acl_fn = catia_fset_nt_acl, + + /* POSIX ACL operations. */ + .chmod_acl_fn = catia_chmod_acl, + .fchmod_acl_fn = catia_fchmod_acl, + + .sys_acl_get_file_fn = catia_sys_acl_get_file, + .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_file_fn = catia_sys_acl_set_file, + .sys_acl_set_fd_fn = catia_sys_acl_set_fd, + .sys_acl_delete_def_file_fn = catia_sys_acl_delete_def_file, + + /* EA operations. */ .getxattr_fn = catia_getxattr, .listxattr_fn = catia_listxattr, .removexattr_fn = catia_removexattr, .setxattr_fn = catia_setxattr, + .fgetxattr_fn = catia_fgetxattr, + .flistxattr_fn = catia_flistxattr, + .fremovexattr_fn = catia_fremovexattr, + .fsetxattr_fn = catia_fsetxattr, }; static_decl_vfs; -- 2.9.3 From 2dd80924c88770511a7bc1e96f5e643723fa3964 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 15:44:56 +0100 Subject: [PATCH 06/60] vfs_catia: add catia_readdir_attr BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit abe3572c59bec0f8da2a79e4ece9de43e8b5e16b) --- source3/modules/vfs_catia.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index eb2e49e..dd8f2dd 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -2253,11 +2253,39 @@ static NTSTATUS catia_set_compression(vfs_handle_struct *handle, return result; } +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 struct vfs_fn_pointers vfs_catia_fns = { /* Directory operations */ .mkdir_fn = catia_mkdir, .rmdir_fn = catia_rmdir, .opendir_fn = catia_opendir, + .readdir_attr_fn = catia_readdir_attr, /* File operations */ .open_fn = catia_open, -- 2.9.3 From 2ce55c6ef8485f89b207d9918abdce935fb88c13 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 17:18:51 +0100 Subject: [PATCH 07/60] vfs_catia: add catia_(g|s)et_dos_attributes BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 633aa1ac10ba4e9d7a97fa026a407defb919ce1a) --- source3/modules/vfs_catia.c | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index dd8f2dd..0ee7c36 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -2280,6 +2280,74 @@ static NTSTATUS catia_readdir_attr(struct vfs_handle_struct *handle, 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 = { /* Directory operations */ .mkdir_fn = catia_mkdir, @@ -2324,6 +2392,8 @@ static struct vfs_fn_pointers vfs_catia_fns = { .strict_unlock_fn = catia_strict_unlock, .translate_name_fn = catia_translate_name, .fsctl_fn = catia_fsctl, + .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, .get_compression_fn = catia_get_compression, -- 2.9.3 From 7e9a68411eb2084a1ff95f550a52f4b32efe4a09 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 16 Nov 2016 09:34:13 +0100 Subject: [PATCH 08/60] vfs_fruit: fix fruit_pread with metadata=stream This make the test "fix offset and len handling for AFP_AfpInfo stream" pass with fruit:metadata=stream. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit d0eed8e73ff39acc6dca70a44f00f81d8ca564fd) --- source3/modules/vfs_fruit.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index d917c73..47ddfb4 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2690,6 +2690,7 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, char *name = NULL; char *tmp_base_name = NULL; NTSTATUS status; + size_t to_return = n; DEBUG(10, ("fruit_pread: offset=%d, size=%d\n", (int)offset, (int)n)); @@ -2719,8 +2720,27 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, } fsp->base_fsp->fsp_name->base_name = name; + if (is_afpinfo_stream(fsp->fsp_name)) { + /* + * 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; + } + + to_return = MIN(n, AFP_INFO_SIZE); + + /* Yes, macOS always reads from offset 0 */ + offset = 0; + } + if (ad == NULL) { - len = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); + len = SMB_VFS_NEXT_PREAD(handle, fsp, data, to_return, offset); if (len == -1) { rc = -1; goto exit; @@ -2735,21 +2755,6 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, if (ad->ad_type == ADOUBLE_META) { char afpinfo_buf[AFP_INFO_SIZE]; - size_t to_return; - - /* - * 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; - } - - to_return = MIN(n, AFP_INFO_SIZE); ai = afpinfo_new(talloc_tos()); if (ai == NULL) { -- 2.9.3 From e4286807cf9903ceb09cfc82ed9c410a629cbaf2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 15 Nov 2016 20:32:05 +0100 Subject: [PATCH 09/60] vfs_fruit: fix fruit_ftruncate with metadata=stream With this the test "setinfo eof AFP_AfpInfo" passed with fruit:metadata=stream. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 04feedb7f6e4519352fdd901356e6e53d97896d5) --- source3/modules/vfs_fruit.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 47ddfb4..8a1e04a 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3323,30 +3323,6 @@ static int fruit_fallocate(struct vfs_handle_struct *handle, return -1; } -static int fruit_ftruncate_meta(struct vfs_handle_struct *handle, - struct files_struct *fsp, - off_t offset, - struct adouble *ad) -{ - struct fruit_config_data *config; - - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct fruit_config_data, return -1); - - 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; - } - - 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(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t offset, @@ -3394,6 +3370,21 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle, DBG_DEBUG("fruit_ftruncate called for file %s offset %.0f\n", fsp_str_dbg(fsp), (double)offset); + if (is_afpinfo_stream(fsp->fsp_name)) { + 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; + } + + DBG_WARNING("ignoring ftruncate %s to %jd", + fsp_str_dbg(fsp), (intmax_t)offset); + /* OS X returns success but does nothing */ + return 0; + } + if (ad == NULL) { return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); } @@ -3403,15 +3394,12 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle, } 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: + DBG_ERR("unexpected ad_type [%d]\n", ad->ad_type); return -1; } -- 2.9.3 From 7b00bd20256cabc2431749b9fde0220ed9388610 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 9 Dec 2016 16:25:38 +0100 Subject: [PATCH 10/60] vfs_fruit: rename empty_finderinfo() and make it more robust No change in behaviour, but ad_entry(ad, ADEID_FINDERI) can in theory return NULL. The next commit will add the same function for a AfpInfo type, so rename this function that works on struct adouble to ad_empty_finderinfo(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 05d54dd71c9797e607c9fa3c5218c13755c7c652) --- source3/modules/vfs_fruit.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 8a1e04a..45eedf2 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -1576,16 +1576,20 @@ static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams, return true; } -static bool empty_finderinfo(const struct adouble *ad) +static bool ad_empty_finderinfo(const struct adouble *ad) { - + int cmp; char emptybuf[ADEDLEN_FINDERI] = {0}; - if (memcmp(emptybuf, - ad_entry(ad, ADEID_FINDERI), - ADEDLEN_FINDERI) == 0) { - return true; + char *fi = NULL; + + fi = ad_entry(ad, ADEID_FINDERI); + if (fi == NULL) { + DBG_ERR("Missing FinderInfo in struct adouble [%p]\n", ad); + return false; } - return false; + + cmp = memcmp(emptybuf, fi, ADEDLEN_FINDERI); + return (cmp == 0); } /** @@ -2871,7 +2875,7 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } memcpy(ad_entry(ad, ADEID_FINDERI), &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - if (empty_finderinfo(ad)) { + if (ad_empty_finderinfo(ad)) { /* Discard metadata */ if (config->meta == FRUIT_META_STREAM) { rc = SMB_VFS_FTRUNCATE(fsp, 0); @@ -3218,7 +3222,7 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, if (config->meta == FRUIT_META_NETATALK) { ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META); - if (ad && !empty_finderinfo(ad)) { + if (ad && !ad_empty_finderinfo(ad)) { if (!add_fruit_stream( mem_ctx, pnum_streams, pstreams, AFPINFO_STREAM_NAME, AFP_INFO_SIZE, -- 2.9.3 From 9f7d294849cd178427d5e72f029fccb35ff89a25 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 15 Nov 2016 21:32:25 +0100 Subject: [PATCH 11/60] vfs_fruit: fix fruit_pwrite() with metadata=stream This makes the test "delete AFP_AfpInfo by writing all 0" pass with fruit:metadata=stream. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b121fff1568b0365ed27655bcd600a8d82cc3489) --- source3/modules/vfs_fruit.c | 83 +++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 45eedf2..2548487 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -1592,6 +1592,15 @@ static bool ad_empty_finderinfo(const struct adouble *ad) 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); +} + /** * Update btime with btime from Netatalk **/ @@ -2847,21 +2856,14 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } fsp->base_fsp->fsp_name->base_name = name; - if (ad == NULL) { - len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); - if (len != n) { - rc = -1; - goto exit; - } - goto exit; - } - - if (!fruit_fsp_recheck(ad, fsp)) { - rc = -1; - goto exit; - } - - if (ad->ad_type == ADOUBLE_META) { + if (is_afpinfo_stream(fsp->fsp_name)) { + /* + * 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) { DEBUG(1, ("unexpected offset=%jd or size=%jd\n", (intmax_t)offset, (intmax_t)n)); @@ -2873,25 +2875,56 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, rc = -1; goto exit; } - memcpy(ad_entry(ad, ADEID_FINDERI), - &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - if (ad_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 (ai_empty_finderinfo(ai)) { + switch (config->meta) { + case FRUIT_META_STREAM: + rc = SMB_VFS_UNLINK(handle->conn, fsp->fsp_name); + break; + + case FRUIT_META_NETATALK: + rc = SMB_VFS_REMOVEXATTR( + handle->conn, + fsp->fsp_name->base_name, + AFPINFO_EA_NETATALK); + break; + + default: + DBG_ERR("Unexpected meta config [%d]\n", + config->meta); + rc = -1; + goto exit; } + 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; } + } + + if (ad == NULL) { + len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); + if (len != n) { + rc = -1; + goto exit; + } + goto exit; + } + + if (!fruit_fsp_recheck(ad, fsp)) { + rc = -1; + goto exit; + } + + if (ad->ad_type == ADOUBLE_META) { + memcpy(ad_entry(ad, ADEID_FINDERI), + &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); + rc = ad_write(ad, name); } else { len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, -- 2.9.3 From a98c2aa7f18f3fd6933cd40a6d72ad757f21bdfe Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 16 Nov 2016 11:01:45 +0100 Subject: [PATCH 12/60] vfs_fruit: replace unsafe ad_entry macro with a function BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 3d5bf4b85f3ca120206a12b3d102aef2ead33082) --- source3/modules/vfs_fruit.c | 113 +++++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 27 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 2548487..423859d 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -341,7 +341,6 @@ 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; @@ -412,6 +411,23 @@ 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, @@ -419,18 +435,19 @@ static int ad_getdate(const struct adouble *ad, uint32_t *date) { bool xlate = (dateoff & AD_DATE_UNIX); + char *p = NULL; dateoff &= AD_DATE_MASK; - if (!ad_getentryoff(ad, ADEID_FILEDATESI)) { + p = ad_get_entry(ad, ADEID_FILEDATESI); + if (p == NULL) { return -1; } if (dateoff > AD_DATE_ACCESS) { return -1; } - memcpy(date, - ad_entry(ad, ADEID_FILEDATESI) + dateoff, - sizeof(uint32_t)); + + memcpy(date, p + dateoff, sizeof(uint32_t)); if (xlate) { *date = AD_DATE_TO_UNIX(*date); @@ -444,9 +461,11 @@ 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; - if (!ad_getentryoff(ad, ADEID_FILEDATESI)) { - return 0; + p = ad_get_entry(ad, ADEID_FILEDATESI); + if (p == NULL) { + return -1; } dateoff &= AD_DATE_MASK; @@ -458,7 +477,7 @@ static int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date) return -1; } - memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date)); + memcpy(p + dateoff, &date, sizeof(date)); return 0; } @@ -944,6 +963,9 @@ static ssize_t ad_header_read_rsrc(struct adouble *ad, const char *path) if ((mode == O_RDWR) && (ad_getentrylen(ad, ADEID_FINDERI) > ADEDLEN_FINDERI)) { + char *p_ad = NULL; + char *p_meta_ad = NULL; + rc = ad_convert(ad, fd); if (rc != 0) { rc = -1; @@ -973,9 +995,18 @@ static ssize_t ad_header_read_rsrc(struct adouble *ad, const char *path) goto exit; } - memcpy(ad_entry(meta_ad, ADEID_FINDERI), - ad_entry(ad, ADEID_FINDERI), - ADEDLEN_FINDERI); + p_ad = ad_get_entry(ad, ADEID_FINDERI); + if (p_ad == NULL) { + rc = -1; + goto exit; + } + p_meta_ad = ad_get_entry(meta_ad, ADEID_FINDERI); + if (p_meta_ad == NULL) { + rc = -1; + goto exit; + } + + memcpy(p_meta_ad, p_ad, ADEDLEN_FINDERI); rc = ad_write(meta_ad, path); if (rc != 0) { @@ -1582,7 +1613,7 @@ static bool ad_empty_finderinfo(const struct adouble *ad) char emptybuf[ADEDLEN_FINDERI] = {0}; char *fi = NULL; - fi = ad_entry(ad, ADEID_FINDERI); + fi = ad_get_entry(ad, ADEID_FINDERI); if (fi == NULL) { DBG_ERR("Missing FinderInfo in struct adouble [%p]\n", ad); return false; @@ -2007,23 +2038,32 @@ static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle, ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META); if (ad) { + char *p = ad_get_entry(ad, ADEID_FINDERI); + + if (p == NULL) { + DBG_ERR("No ADEID_FINDERI for [%s]\n", + smb_fname->base_name); + status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + 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); + p, 4); /* finder_creator */ memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4, - ad_entry(ad, ADEID_FINDERI) + 4, 4); + p + 4, 4); } /* finder_flags */ memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8, - ad_entry(ad, ADEID_FINDERI) + 8, 2); + p + 8, 2); /* finder_ext_flags */ memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10, - ad_entry(ad, ADEID_FINDERI) + 24, 2); + p + 24, 2); /* creation date */ date_added = convert_time_t_to_uint32_t( @@ -2034,6 +2074,7 @@ static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle, } } +out: TALLOC_FREE(ad); return status; } @@ -2768,6 +2809,7 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, if (ad->ad_type == ADOUBLE_META) { char afpinfo_buf[AFP_INFO_SIZE]; + char *p = NULL; ai = afpinfo_new(talloc_tos()); if (ai == NULL) { @@ -2781,9 +2823,16 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, goto exit; } - memcpy(&ai->afpi_FinderInfo[0], - ad_entry(ad, ADEID_FINDERI), - ADEDLEN_FINDERI); + p = ad_get_entry(ad, ADEID_FINDERI); + if (p == NULL) { + DBG_ERR("No ADEID_FINDERI for [%s]\n", + fsp->fsp_name->base_name); + rc = -1; + goto exit; + } + + memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI); + len = afpinfo_pack(ai, afpinfo_buf); if (len != AFP_INFO_SIZE) { rc = -1; @@ -2922,9 +2971,17 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } if (ad->ad_type == ADOUBLE_META) { - memcpy(ad_entry(ad, ADEID_FINDERI), - &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); + char *p = NULL; + p = ad_get_entry(ad, ADEID_FINDERI); + if (p == NULL) { + DBG_ERR("No ADEID_FINDERI for [%s]\n", + fsp->fsp_name->base_name); + rc = -1; + goto exit; + } + + memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); rc = ad_write(ad, name); } else { len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, @@ -3253,14 +3310,16 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, DEBUG(10, ("fruit_streaminfo called for %s\n", smb_fname->base_name)); if (config->meta == FRUIT_META_NETATALK) { + bool ok; + ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META); - if (ad && !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))) { + if ((ad != NULL) && !ad_empty_finderinfo(ad)) { + ok = add_fruit_stream( + mem_ctx, pnum_streams, pstreams, + AFPINFO_STREAM_NAME, AFP_INFO_SIZE, + smb_roundup(handle->conn, AFP_INFO_SIZE)); + if (!ok) { TALLOC_FREE(ad); return NT_STATUS_NO_MEMORY; } -- 2.9.3 From 4013b3206e706658248d1348659020d679c0f9cf Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 29 Nov 2016 16:56:00 +0100 Subject: [PATCH 13/60] vfs_fruit: refactor fruit_open_meta() Just split out the fruit:metadata=stream case into a helper function, no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 5a072ca91c642e61b36f1670105f6c8d1e64e25c) --- source3/modules/vfs_fruit.c | 59 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 423859d..07ba1ba 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2185,26 +2185,27 @@ static int fruit_connect(vfs_handle_struct *handle, return rc; } -static int fruit_open_meta(vfs_handle_struct *handle, - struct smb_filename *smb_fname, - files_struct *fsp, int flags, mode_t mode) +static int fruit_open_meta_stream(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + files_struct *fsp, + int flags, + mode_t mode) +{ + return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); +} + +static int fruit_open_meta_netatalk(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; - 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(), smb_fname->base_name, @@ -2297,6 +2298,38 @@ exit: return hostfd; } +static int fruit_open_meta(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + files_struct *fsp, int flags, mode_t mode) +{ + int rc; + struct fruit_config_data *config = 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: + rc = fruit_open_meta_stream(handle, smb_fname, + fsp, flags, mode); + break; + + case FRUIT_META_NETATALK: + rc = 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] rc [%d]\n", smb_fname_str_dbg(smb_fname), rc); + return rc; +} + static int fruit_open_rsrc(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) -- 2.9.3 From f4aa1359bb57ec9576f71cf974a6dcf846fdcffc Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 9 Dec 2016 17:01:37 +0100 Subject: [PATCH 14/60] vfs_fruit: correct fruit_open_meta_stream() implementation This needs to create and write a metadata blob when the stream is created. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit a3be9e69c3d3ff4980b47261dc0d043a0275a8c0) --- source3/modules/vfs_fruit.c | 55 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 07ba1ba..f0bd58b 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2191,7 +2191,60 @@ static int fruit_open_meta_stream(vfs_handle_struct *handle, int flags, mode_t mode) { - return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, 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); + fsp->fh->fd = -1; + if (written != AFP_INFO_SIZE) { + DBG_ERR("bad write [%zd/%d]\n", written, AFP_INFO_SIZE); + rc = -1; + goto fail; + } + + rc = 0; + +fail: + DBG_DEBUG("rc=%d, fd=%d\n", rc, hostfd); + + if (rc != 0) { + int saved_errno = errno; + if (hostfd >= 0) { + fsp->fh->fd = hostfd; + SMB_VFS_NEXT_CLOSE(handle, fsp); + } + hostfd = -1; + errno = saved_errno; + } + return hostfd; } static int fruit_open_meta_netatalk(vfs_handle_struct *handle, -- 2.9.3 From 019067b6bc44de102052fba997d9ee3ff6f447bd Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 11:05:50 +0100 Subject: [PATCH 15/60] vfs_fruit: refactor fruit_stat_meta() Handle config->meta in helper functions. No change in behaviour. The next step will add the correct implementation of fruit_stat_meta_stream(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit aaf2ae1b2b1a2822bff6140dfd7afde1569c2548) --- source3/modules/vfs_fruit.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index f0bd58b..695e3f9 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3122,9 +3122,9 @@ static int fruit_stat_base(vfs_handle_struct *handle, return rc; } -static int fruit_stat_meta(vfs_handle_struct *handle, - struct smb_filename *smb_fname, - bool follow_links) +static int fruit_stat_meta_netatalk(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + bool follow_links) { struct adouble *ad = NULL; @@ -3147,6 +3147,30 @@ static int fruit_stat_meta(vfs_handle_struct *handle, return 0; } +static int fruit_stat_meta(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: + 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(vfs_handle_struct *handle, struct smb_filename *smb_fname, bool follow_links) -- 2.9.3 From 88851b648dbb9e9f0f1a51c1966fdcfc0211632a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 11:12:18 +0100 Subject: [PATCH 16/60] vfs_fruit: correct fruit_stat_meta_stream() implementation BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit cb1121ec3268fecb7fa0f5fbb6d2dbffaea991b3) --- source3/modules/vfs_fruit.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 695e3f9..184276f 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3122,6 +3122,21 @@ static int fruit_stat_base(vfs_handle_struct *handle, 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); + } else { + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); + } + + return ret; +} + static int fruit_stat_meta_netatalk(vfs_handle_struct *handle, struct smb_filename *smb_fname, bool follow_links) @@ -3159,6 +3174,9 @@ static int fruit_stat_meta(vfs_handle_struct *handle, 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; -- 2.9.3 From 4c9c89fbb8dd346cc92823668e10bf3dd1062a3c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 17:25:47 +0100 Subject: [PATCH 17/60] vfs_fruit: update_btime() is only needed for metadata=netatalk BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 79159f8dc95057187601ac167414cc49282bdabf) --- source3/modules/vfs_fruit.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 184276f..1394b9a 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -1641,6 +1641,21 @@ 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) { -- 2.9.3 From 2283ede871310e3ebf5dd4f6d5784f17f82bed14 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 1 Dec 2016 17:04:35 +0100 Subject: [PATCH 18/60] vfs_fruit: refactor readdir_attr_meta() Move the FinderInfo stuff to helper functions, no change in behaviour so far. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 5a466560b2811c78d731cc039c99c740ddee5ffc) --- source3/modules/vfs_fruit.c | 137 +++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 39 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 1394b9a..67a48a8 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2014,14 +2014,108 @@ 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) +{ + return true; +} + +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; + + ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META); + if (ad == NULL) { + return false; + } + + 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; + } + + memcpy(&ai->afpi_FinderInfo[0], p, AFP_FinderSize); + TALLOC_FREE(ad); + return true; +} + +static bool readdir_attr_meta_finderi(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + struct readdir_attr_data *attr_data) +{ + struct fruit_config_data *config = NULL; + uint32_t date_added; + AfpInfo ai = {0}; + bool ok; + + 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; + } + + if (!ok) { + /* Don't bother with errors, it's likely ENOENT */ + return true; + } + + 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); + + /* finder_creator */ + memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4, + &ai.afpi_FinderInfo[4], 4); + } + + /* 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); + + /* 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); + + return true; +} + 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; - uint32_t date_added; struct adouble *ad = NULL; struct fruit_config_data *config = NULL; + bool ok; SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, @@ -2050,47 +2144,12 @@ static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle, */ if (config->readdir_attr_finder_info) { - ad = ad_get(talloc_tos(), handle, smb_fname->base_name, - ADOUBLE_META); - if (ad) { - char *p = ad_get_entry(ad, ADEID_FINDERI); - - if (p == NULL) { - DBG_ERR("No ADEID_FINDERI for [%s]\n", - smb_fname->base_name); - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - - if (S_ISREG(smb_fname->st.st_ex_mode)) { - /* finder_type */ - memcpy(&attr_data->attr_data.aapl.finder_info[0], - p, 4); - - /* finder_creator */ - memcpy(&attr_data->attr_data.aapl.finder_info[0] + 4, - p + 4, 4); - } - - /* finder_flags */ - memcpy(&attr_data->attr_data.aapl.finder_info[0] + 8, - p + 8, 2); - - /* finder_ext_flags */ - memcpy(&attr_data->attr_data.aapl.finder_info[0] + 10, - p + 24, 2); - - /* 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); - - TALLOC_FREE(ad); + ok = readdir_attr_meta_finderi(handle, smb_fname, attr_data); + if (!ok) { + status = NT_STATUS_INTERNAL_ERROR; } } -out: - TALLOC_FREE(ad); return status; } -- 2.9.3 From ae1e566bd3afdd276b51d812f43822f91fca57c2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 9 Dec 2016 17:24:18 +0100 Subject: [PATCH 19/60] vfs_fruit: correct readdir_attr_meta_finderi_stream() implementation This gets correct behaviour in readdir_attr_meta_finderi for the metadata=stream case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 604bd6bf80285db2e52266708d55215f07503c73) --- source3/modules/vfs_fruit.c | 68 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 67a48a8..7c16678 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2019,7 +2019,73 @@ static bool readdir_attr_meta_finderi_stream( const struct smb_filename *smb_fname, AfpInfo *ai) { - return true; + 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]; + + stream_name = synthetic_smb_fname(talloc_tos(), + smb_fname->base_name, + AFPINFO_STREAM_NAME, + NULL, smb_fname->flags); + if (stream_name == NULL) { + return false; + } + + 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); + + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + 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; + } + + memcpy(&ai->afpi_FinderInfo[0], &buf[AFP_OFF_FinderInfo], + AFP_FinderSize); + + ok = true; + +fail: + if (fsp != NULL) { + close_file(NULL, fsp, NORMAL_CLOSE); + } + + return ok; } static bool readdir_attr_meta_finderi_netatalk( -- 2.9.3 From df17e6c1f027f1a9f4c18a13f9f45b7ce7923e28 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 08:47:36 +0100 Subject: [PATCH 20/60] vfs_fruit: fix fruit_rename() for the fruit:resource!=file case o fix the config check, we must only run following code for the fruit:resource=file o properly call SMB_VFS_NEXT_RENAME() instead diretly calling rename() o bail out if we get an invalid stat Otherwise, no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 8a9d0c541875d06254dc3a3039b20c8acac328ed) --- source3/modules/vfs_fruit.c | 55 +++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 7c16678..1c92dd7 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2688,19 +2688,27 @@ 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; - rc = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); + SMB_VFS_HANDLE_GET_DATA(handle, config, + struct fruit_config_data, return -1); - if (!VALID_STAT(smb_fname_src->st) - || !S_ISREG(smb_fname_src->st.st_ex_mode)) { - return rc; + if (!VALID_STAT(smb_fname_src->st)) { + DBG_ERR("Need valid stat for [%s]\n", + smb_fname_str_dbg(smb_fname_src)); + return -1; } - 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 (rc != 0) { + return -1; + } - if (config->rsrc == FRUIT_RSRC_XATTR) { - return rc; + if ((config->rsrc != FRUIT_RSRC_ADFILE) || + (!S_ISREG(smb_fname_src->st.st_ex_mode))) + { + return 0; } rc = adouble_path(talloc_tos(), smb_fname_src->base_name, @@ -2708,24 +2716,43 @@ 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; + } - DEBUG(10, ("fruit_rename: %s -> %s\n", - src_adouble_path, dst_adouble_path)); + DBG_DEBUG("%s -> %s\n", + smb_fname_str_dbg(src_adp_smb_fname), + smb_fname_str_dbg(dst_adp_smb_fname)); - rc = rename(src_adouble_path, dst_adouble_path); + rc = SMB_VFS_NEXT_RENAME(handle, src_adp_smb_fname, dst_adp_smb_fname); 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; } -- 2.9.3 From 60abde6f388a6846bc41425dde279fd97d9b5649 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 09:00:31 +0100 Subject: [PATCH 21/60] vfs_fruit: refactor fruit_unlink() Refactor fruit_unlink() addin helper functions for all fruit:metadata and fruit:resource settings. No change in behaviour for fruit:metadata=netatalk and fruit:resource=file (both the default), but fixes behaviour for the other cases. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 6730e1035ba740d0de413256a211937c3bd794e1) --- source3/modules/vfs_fruit.c | 230 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 197 insertions(+), 33 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 1c92dd7..036d7ad 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2756,25 +2756,59 @@ done: return rc; } -static int fruit_unlink(vfs_handle_struct *handle, - const struct smb_filename *smb_fname) +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) { - int rc = -1; struct fruit_config_data *config = NULL; + int rc; SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - if (!is_ntfs_stream_smb_fname(smb_fname)) { - char *adp = NULL; + switch (config->meta) { + case FRUIT_META_STREAM: + rc = fruit_unlink_meta_stream(handle, smb_fname); + break; - rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname); - if (rc != 0) { - return -1; - } + case FRUIT_META_NETATALK: + rc = fruit_unlink_meta_netatalk(handle, smb_fname); + break; - if (config->rsrc != FRUIT_RSRC_ADFILE) { - return 0; + 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; + + smb_fname_cp = cp_smb_filename(talloc_tos(), smb_fname); + if (smb_fname_cp == NULL) { + return -1; } /* @@ -2782,46 +2816,176 @@ static int fruit_unlink(vfs_handle_struct *handle, * vfs_streaminfo, as a result stream cleanup/deletion of file * deletion doesn't remove the resourcefork stream. */ - rc = adouble_path(talloc_tos(), - smb_fname->base_name, &adp); - if (rc != 0) { + + 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)); return -1; } - /* FIXME: direct unlink(), missing smb_fname */ - DBG_DEBUG("fruit_unlink: %s\n", adp); - rc = unlink(adp); - if ((rc == -1) && (errno == ENOENT)) { - rc = 0; + 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; } + } - TALLOC_FREE(adp); - return 0; + ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname); + if ((ret != 0) && (errno == ENOENT) && force_unlink) { + ret = 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); + 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; } - return rc; + + /* + * 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; + } + + TALLOC_FREE(ad); } - if (is_afpresource_stream(smb_fname)) { - /* OS X ignores deletes on the AFP_Resource stream */ - return 0; + rc = adouble_path(talloc_tos(), smb_fname->base_name, &adp); + if (rc != 0) { + return -1; } - return SMB_VFS_NEXT_UNLINK(handle, smb_fname); + adp_smb_fname = synthetic_smb_fname(talloc_tos(), adp, + NULL, NULL, + smb_fname->flags); + TALLOC_FREE(adp); + if (adp_smb_fname == NULL) { + return -1; + } + + rc = SMB_VFS_NEXT_UNLINK(handle, adp_smb_fname); + TALLOC_FREE(adp_smb_fname); + if ((rc != 0) && (errno == ENOENT) && force_unlink) { + rc = 0; + } + return rc; +} +static int fruit_unlink_rsrc_xattr(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + bool force_unlink) +{ + /* + * OS X ignores resource fork stream delete requests, so nothing to do + * here. Removing the file will remove the xattr anyway, so we don't + * have to take care of removing 0 byte resource forks that could be + * left behind. + */ 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) -- 2.9.3 From b6279f138fa5a67ec64d56dccc083e9390c65692 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 09:02:27 +0100 Subject: [PATCH 22/60] vfs_fruit: fix fruit_chmod() for the fruit:resource!=file case The following code must only be executed for the fruit:resource=file case. While at it, remove an unnecessary lstat, use the stat info from smb_fname. Otherwise no change in behaviour for the fruit:resource=file case (the default). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 22b509f52ed4de0856432327b3bf78fedcde141b) --- source3/modules/vfs_fruit.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 036d7ad..2e559b3 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2993,7 +2993,6 @@ 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; @@ -3005,14 +3004,16 @@ 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_XATTR) { + if (config->rsrc != FRUIT_RSRC_ADFILE) { 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; + if (!VALID_STAT(smb_fname->st)) { + return 0; + } + + if (!S_ISREG(smb_fname->st.st_ex_mode)) { + return 0; } rc = adouble_path(talloc_tos(), path, &adp); -- 2.9.3 From 3cc085823cba60219f2b963f3961b06e6f0bdd1d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 09:04:37 +0100 Subject: [PATCH 23/60] vfs_fruit: fix fruit_chown() for the fruit:resource!=file case The following code must only be executed for the fruit:resource=file case. While at it, remove an unnecessary lstat, use the stat info from smb_fname. Otherwise no change in behaviour for the fruit:resource=file case (the default). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 09c82a1ce192112a7264d19f6d8888bad49f6a82) --- source3/modules/vfs_fruit.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 2e559b3..32659da 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3053,7 +3053,6 @@ 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) { @@ -3063,14 +3062,16 @@ 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_XATTR) { - return rc; + if (config->rsrc != FRUIT_RSRC_ADFILE) { + 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; + if (!VALID_STAT(smb_fname->st)) { + return 0; + } + + if (!S_ISREG(smb_fname->st.st_ex_mode)) { + return 0; } rc = adouble_path(talloc_tos(), smb_fname->base_name, &adp); -- 2.9.3 From 5ba0b3d05d41bfbc5b8d39b5cb70d2d866e7b961 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 9 Dec 2016 18:22:49 +0100 Subject: [PATCH 24/60] vfs_fruit: fix fruit_rmdir() for the fruit:resource!=file case The following code must only be executed for the fruit:resource=file case. Otherwise no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 19854072dbb7a9ba97d48f4012ea3a238721fc58) --- source3/modules/vfs_fruit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 32659da..c17cdbb 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3114,7 +3114,7 @@ static int fruit_rmdir(struct vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - if (!handle->conn->cwd || !path || (config->rsrc == FRUIT_RSRC_XATTR)) { + if (config->rsrc != FRUIT_RSRC_ADFILE) { goto exit_rmdir; } -- 2.9.3 From 4627f8966336ed77541e90d3f7dbcf61eb08424a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 9 Dec 2016 18:24:40 +0100 Subject: [PATCH 25/60] vfs_fruit: in fruit_rmdir() check ._ files before deleting them This ensures we only delete valid AppleDouble files whose names begin with "._", not just *any* file that matches "^._*". Also use proper VFS functions instead of direclty calling the C library functions. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b95d2042e51ad4c2854e3b2465d55a063bc19f95) --- source3/modules/vfs_fruit.c | 61 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index c17cdbb..2a46094 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3109,7 +3109,6 @@ 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); @@ -3122,24 +3121,58 @@ 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 = opendir(path); + + dh = SMB_VFS_OPENDIR(handle->conn, smb_fname, NULL, 0); if (dh == NULL) { goto exit_rmdir; } - 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); + 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) { 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)); } } -- 2.9.3 From 1167d5fbf7e95bfa810b2d41a6fc1fcb09b0c16e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 10:46:55 +0100 Subject: [PATCH 26/60] vfs_fruit: refactor fruit_open_rsrc() This just splits up fruit_open_rsrc() to use helper functions for each config->rsrc setting. No change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 22da6c82f08ed82cf7eddb3fdda2b6ab66264683) --- source3/modules/vfs_fruit.c | 105 ++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 2a46094..13aef1f 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2523,47 +2523,18 @@ static int fruit_open_meta(vfs_handle_struct *handle, return rc; } -static int fruit_open_rsrc(vfs_handle_struct *handle, - struct smb_filename *smb_fname, - files_struct *fsp, int flags, mode_t mode) +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; 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) { @@ -2660,6 +2631,72 @@ 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; + struct adouble *ad = NULL; + + ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), + handle, ADOUBLE_RSRC, fsp); + if (ad == NULL) { + return -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; + + 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); + return fd; +} + static int fruit_open(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) -- 2.9.3 From 4775798fe5bdaa9bc278e933bd1d24abee4728a8 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 11:26:22 +0100 Subject: [PATCH 27/60] vfs_fruit: refactor fruit_stat_rsrc() Use helper functions for the fruit:resource cases. No change in behaveour. The next patch will add the proper helper functions for fruit:resource=xattr and fruit:resource=stream. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 5037816d28df6f1eed46abf910b0cd4c1a40ec77) --- source3/modules/vfs_fruit.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 13aef1f..3442de6 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3592,15 +3592,12 @@ static int fruit_stat_meta(vfs_handle_struct *handle, return ret; } -static int fruit_stat_rsrc(vfs_handle_struct *handle, - struct smb_filename *smb_fname, - bool follow_links) - +static int fruit_stat_rsrc_netatalk(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + bool follow_links) { struct adouble *ad = NULL; - - DEBUG(10, ("fruit_stat_rsrc called for %s\n", - smb_fname_str_dbg(smb_fname))); + int ret; ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_RSRC); if (ad == NULL) { @@ -3609,7 +3606,8 @@ static int fruit_stat_rsrc(vfs_handle_struct *handle, } /* Populate the stat struct with info from the base file. */ - if (fruit_stat_base(handle, smb_fname, follow_links) == -1) { + ret = fruit_stat_base(handle, smb_fname, follow_links); + if (ret != 0) { TALLOC_FREE(ad); return -1; } @@ -3621,6 +3619,33 @@ static int fruit_stat_rsrc(vfs_handle_struct *handle, return 0; } +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: + case FRUIT_RSRC_XATTR: + 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) { -- 2.9.3 From 247396bb9d3bb2399c9e1559e5b1bd6ae02891ed Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 11:30:06 +0100 Subject: [PATCH 28/60] vfs_fruit: add fruit_stat_rsrc_stream() implementation This fixes fruit_stat_rsrc for the fruit:resource=stream case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit cbf87b46c2ad7d0795616c517d3e39f24d827ef4) --- source3/modules/vfs_fruit.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 3442de6..681a9e7 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3619,6 +3619,21 @@ 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(vfs_handle_struct *handle, struct smb_filename *smb_fname, bool follow_links) @@ -3633,6 +3648,9 @@ static int fruit_stat_rsrc(vfs_handle_struct *handle, switch (config->rsrc) { case FRUIT_RSRC_STREAM: + ret = fruit_stat_rsrc_stream(handle, smb_fname, follow_links); + break; + case FRUIT_RSRC_XATTR: case FRUIT_RSRC_ADFILE: ret = fruit_stat_rsrc_netatalk(handle, smb_fname, follow_links); -- 2.9.3 From b53be2ed60e4a3d57903c2a95019b633705b233a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 11:44:53 +0100 Subject: [PATCH 29/60] vfs_fruit: add fruit_stat_rsrc_xattr() implementation This fixes fruit_stat_rsrc for the fruit:resource=xattr case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 72325d946aacc1beec0eb411f4c7209e06850e91) --- source3/modules/vfs_fruit.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 681a9e7..375087f 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3634,6 +3634,48 @@ static int fruit_stat_rsrc_stream(vfs_handle_struct *handle, 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) @@ -3652,6 +3694,9 @@ static int fruit_stat_rsrc(vfs_handle_struct *handle, 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; -- 2.9.3 From df85204fddc90fdb932f9541ea9aa6489df504b2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 15:49:03 +0100 Subject: [PATCH 30/60] vfs_fruit: refactor fruit_streaminfo() Handle all settings of fruit:metadata and fruit:resource in helper functions. Resource fork streams of 0 bytes must be filtered out, this wasn't done previously for the fruit:resource=stream and xattr case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit ef2c81eb9fe5e12d5694af665be198994e02762d) --- source3/modules/vfs_fruit.c | 309 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 265 insertions(+), 44 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 375087f..4b18364 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -1576,6 +1576,40 @@ 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) @@ -3913,6 +3947,226 @@ exit: 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) +{ + return NT_STATUS_OK; +} + +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) +{ + struct adouble *ad = NULL; + bool is_fi_empty; + bool ok; + + /* 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; + } + + ad = ad_get(talloc_tos(), handle, + smb_fname->base_name, ADOUBLE_META); + if (ad == NULL) { + return NT_STATUS_OK; + } + + is_fi_empty = ad_empty_finderinfo(ad); + TALLOC_FREE(ad); + + if (is_fi_empty) { + return NT_STATUS_OK; + } + + 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; + } + + return NT_STATUS_OK; +} + +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) +{ + 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->meta) { + case FRUIT_META_NETATALK: + status = fruit_streaminfo_meta_netatalk(handle, fsp, smb_fname, + mem_ctx, pnum_streams, + pstreams); + break; + + case FRUIT_META_STREAM: + status = fruit_streaminfo_meta_stream(handle, fsp, smb_fname, + mem_ctx, pnum_streams, + pstreams); + break; + + default: + return NT_STATUS_INTERNAL_ERROR; + } + + 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; + } + return NT_STATUS_OK; +} + +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; + + 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; +} + +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) +{ + struct stream_struct *stream = *pstreams; + unsigned int num_streams = *pnum_streams; + struct adouble *ad = NULL; + bool ok; + size_t rlen; + int i; + + /* + * Check if there's a AFPRESOURCE_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, AFPRESOURCE_STREAM)) { + break; + } + } + + if (i < num_streams) { + DBG_WARNING("Unexpected AFPRESOURCE_STREAM on [%s]\n", + smb_fname_str_dbg(smb_fname)); + + ok = del_fruit_stream(mem_ctx, pnum_streams, pstreams, + AFPRESOURCE_STREAM); + if (!ok) { + return NT_STATUS_INTERNAL_ERROR; + } + } + + ad = ad_get(talloc_tos(), handle, smb_fname->base_name, + ADOUBLE_RSRC); + if (ad == NULL) { + return NT_STATUS_OK; + } + + rlen = ad_getentrylen(ad, ADEID_RFORK); + TALLOC_FREE(ad); + + if (rlen == 0) { + return NT_STATUS_OK; + } + + 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; + } + + 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; + + case FRUIT_RSRC_XATTR: + status = fruit_streaminfo_rsrc_xattr(handle, fsp, smb_fname, + mem_ctx, pnum_streams, + pstreams); + break; + + case FRUIT_RSRC_ADFILE: + status = fruit_streaminfo_rsrc_adouble(handle, fsp, smb_fname, + mem_ctx, pnum_streams, + pstreams); + break; + + default: + return NT_STATUS_INTERNAL_ERROR; + } + + return status; +} + static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, struct files_struct *fsp, const struct smb_filename *smb_fname, @@ -3921,48 +4175,12 @@ 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) { - bool ok; - - ad = ad_get(talloc_tos(), handle, - smb_fname->base_name, ADOUBLE_META); - if ((ad != NULL) && !ad_empty_finderinfo(ad)) { - ok = add_fruit_stream( - mem_ctx, pnum_streams, pstreams, - AFPINFO_STREAM_NAME, AFP_INFO_SIZE, - smb_roundup(handle->conn, AFP_INFO_SIZE)); - if (!ok) { - TALLOC_FREE(ad); - return NT_STATUS_NO_MEMORY; - } - } - TALLOC_FREE(ad); - } - 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); - } + DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname)); status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname, mem_ctx, pnum_streams, pstreams); @@ -3970,13 +4188,16 @@ static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle, 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; - } + 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; } return NT_STATUS_OK; -- 2.9.3 From fa114bef1e2ab14e779569e8e83ec262ea6bc827 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 15:57:22 +0100 Subject: [PATCH 31/60] vfs_fruit: fix fruit_ntimes() for the fruit:metadata!=netatalk case The following code must only be executed for the fruit:metadata=netatalk case. Otherwise no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b0b785b0d4b64810f6ee58b015929641246479d1) --- source3/modules/vfs_fruit.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 4b18364..388f8f8 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4209,9 +4209,15 @@ static int fruit_ntimes(vfs_handle_struct *handle, { int rc = 0; struct adouble *ad = NULL; + struct fruit_config_data *config = NULL; - if (null_timespec(ft->create_time)) { - goto exit; + 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); } DEBUG(10,("set btime for %s to %s\n", smb_fname_str_dbg(smb_fname), -- 2.9.3 From bd916f514be92db46e155f45145fbe97d086fab6 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 16:20:46 +0100 Subject: [PATCH 32/60] vfs_fruit: refactor fruit_ftruncate() and fix stream case The fruit:metadata=stream case wasn't handled previosly, this is now done in fruit_ftruncate_rsrc_stream(). The rest is just refactoring and no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit a5b060fcd2c1d26bd0abfceffcd7b2c43056c78e) --- source3/modules/vfs_fruit.c | 120 ++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 388f8f8..5fc6fbd 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4265,50 +4265,100 @@ static int fruit_fallocate(struct vfs_handle_struct *handle, 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); + } + +#ifdef HAVE_ATTROPEN + return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); +#endif + return 0; +} + +static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, + struct files_struct *fsp, + off_t offset) +{ + int rc; + struct adouble *ad = + (struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + off_t ad_off = ad_getentryoff(ad, ADEID_RFORK); + + if (!fruit_fsp_recheck(ad, fsp)) { + return -1; + } + + rc = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset + ad_off); + if (rc != 0) { + return -1; + } + + ad_setentrylen(ad, ADEID_RFORK, offset); + + rc = ad_write(ad, NULL); + if (rc != 0) { + DBG_ERR("ad_write [%s] failed [%s]\n", + fsp_str_dbg(fsp), strerror(errno)); + return -1; + } + + DBG_DEBUG("Path [%s] offset [%jd]\n", + fsp_str_dbg(fsp), (intmax_t)offset); + + 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, - struct adouble *ad) + off_t offset) { - int rc; + int ret; struct fruit_config_data *config; SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - if (config->rsrc == FRUIT_RSRC_XATTR && offset == 0) { - return SMB_VFS_FREMOVEXATTR(fsp, - AFPRESOURCE_EA_NETATALK); - } + switch (config->rsrc) { + case FRUIT_RSRC_XATTR: + ret = fruit_ftruncate_rsrc_xattr(handle, fsp, offset); + break; - rc = SMB_VFS_NEXT_FTRUNCATE( - handle, fsp, - offset + ad_getentryoff(ad, ADEID_RFORK)); - if (rc != 0) { + case FRUIT_RSRC_ADFILE: + ret = fruit_ftruncate_rsrc_adouble(handle, fsp, offset); + break; + + case FRUIT_RSRC_STREAM: + ret = fruit_ftruncate_rsrc_stream(handle, fsp, offset); + break; + + default: + DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc); return -1; } - if (config->rsrc == FRUIT_RSRC_ADFILE) { - ad_setentrylen(ad, ADEID_RFORK, offset); - rc = ad_write(ad, NULL); - if (rc != 0) { - return -1; - } - DEBUG(10, ("fruit_ftruncate_rsrc file %s offset %jd\n", - fsp_str_dbg(fsp), (intmax_t)offset)); - } - return 0; + return ret; } static int fruit_ftruncate(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t offset) { - int rc = 0; - struct adouble *ad = - (struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp); - DBG_DEBUG("fruit_ftruncate called for file %s offset %.0f\n", fsp_str_dbg(fsp), (double)offset); @@ -4327,25 +4377,11 @@ static int fruit_ftruncate(struct vfs_handle_struct *handle, return 0; } - if (ad == NULL) { - return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); - } - - if (!fruit_fsp_recheck(ad, fsp)) { - return -1; - } - - switch (ad->ad_type) { - case ADOUBLE_RSRC: - rc = fruit_ftruncate_rsrc(handle, fsp, offset, ad); - break; - - default: - DBG_ERR("unexpected ad_type [%d]\n", ad->ad_type); - return -1; + if (is_afpresource_stream(fsp->fsp_name)) { + return fruit_ftruncate_rsrc(handle, fsp, offset); } - return rc; + return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); } static NTSTATUS fruit_create_file(vfs_handle_struct *handle, -- 2.9.3 From 9f42edd1871330d9dbfa211e37a50e0d64398981 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 17:00:03 +0100 Subject: [PATCH 33/60] vfs_fruit: refactor readdir_attr_macmeta() resource fork size Move resource fork size calculation to helper functions. Adds correct handling for the fruit:resource=stream case in readdir_attr_rfork_size_stream(), this wasn't done previously. Otherwise no change in behaviour. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit ad8a3b6971945fbceeef8763613a9e5f5a475098) --- source3/modules/vfs_fruit.c | 90 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 5fc6fbd..e5ab2a2 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2208,12 +2208,89 @@ static bool readdir_attr_meta_finderi(struct vfs_handle_struct *handle, return true; } +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; + + 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 adouble *ad = NULL; struct fruit_config_data *config = NULL; bool ok; @@ -2230,13 +2307,10 @@ static NTSTATUS readdir_attr_macmeta(struct vfs_handle_struct *handle, */ 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); - } + uint64_t rfork_size; + + rfork_size = readdir_attr_rfork_size(handle, smb_fname); + attr_data->attr_data.aapl.rfork_size = rfork_size; } /* -- 2.9.3 From 46f93f78b66ebaa20aebbbbbc6c018aa2597a5b1 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 8 Feb 2017 19:15:38 +0100 Subject: [PATCH 34/60] vfs_fruit: use SMB_VFS_NEXT_OPEN in two places Using the SMB_VFS_OPEN leads to a logic recursion that is hard to follow and debug. It may be called twice for the same fsp with two different smb_fname's. Changing this here to use the NEXT function instead should have no change in behaviour otherwise, but it allows adding sane caching to vfs_catia to handle based VFS ops. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 3e2a7f6227204e932a8337fe77cdda22d28f85f6) --- source3/modules/vfs_fruit.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index e5ab2a2..9d7003e 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2529,8 +2529,8 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle, baseflags &= ~O_EXCL; baseflags &= ~O_CREAT; - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, - baseflags, mode); + hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, + baseflags, mode); /* * It is legit to open a stream on a directory, but the base @@ -2539,8 +2539,8 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle, if ((hostfd == -1) && (errno == EISDIR)) { baseflags &= ~O_ACCMODE; baseflags |= O_RDONLY; - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, - baseflags, mode); + hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, + baseflags, mode); } TALLOC_FREE(smb_fname_base); @@ -2591,7 +2591,7 @@ exit: * full fsp yet */ fsp->fh->fd = hostfd; - SMB_VFS_CLOSE(fsp); + SMB_VFS_NEXT_CLOSE(handle, fsp); } hostfd = -1; errno = saved_errno; @@ -2681,8 +2681,8 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, flags |= O_RDWR; } - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp, - flags, mode); + hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, + flags, mode); if (hostfd == -1) { rc = -1; goto exit; -- 2.9.3 From 9d2c3d7c508ff44f87a33976bc4fbcd556a0fe91 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2016 15:07:20 +0100 Subject: [PATCH 35/60] vfs_fruit: remove base_fsp name translation This is now nicely done by vfs_catia for us. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b1223520e3d35f59e0f77648e0afdf049e1c9de3) --- source3/modules/vfs_fruit.c | 83 ++------------------------------------------- 1 file changed, 3 insertions(+), 80 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 9d7003e..59e7862 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3338,9 +3338,6 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, struct fruit_config_data *config = NULL; AfpInfo *ai = NULL; ssize_t len = -1; - char *name = NULL; - char *tmp_base_name = NULL; - NTSTATUS status; size_t to_return = n; DEBUG(10, ("fruit_pread: offset=%d, size=%d\n", (int)offset, (int)n)); @@ -3352,25 +3349,6 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, 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; - if (is_afpinfo_stream(fsp->fsp_name)) { /* * OS X has a off-by-1 error in the offset calculation, so we're @@ -3451,8 +3429,6 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, } } exit: - fsp->base_fsp->fsp_name->base_name = tmp_base_name; - TALLOC_FREE(name); TALLOC_FREE(ai); if (rc != 0) { len = -1; @@ -3471,9 +3447,6 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, struct fruit_config_data *config = NULL; AfpInfo *ai = NULL; ssize_t len; - char *name = NULL; - char *tmp_base_name = NULL; - NTSTATUS status; DEBUG(10, ("fruit_pwrite: offset=%d, size=%d\n", (int)offset, (int)n)); @@ -3484,24 +3457,6 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, 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; - } - } 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; - if (is_afpinfo_stream(fsp->fsp_name)) { /* * Writing an all 0 blob to the metadata stream @@ -3579,7 +3534,7 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - rc = ad_write(ad, name); + rc = ad_write(ad, fsp->base_fsp->fsp_name->base_name); } else { len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset + ad_getentryoff(ad, ADEID_RFORK)); @@ -3589,7 +3544,7 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } if (config->rsrc == FRUIT_RSRC_ADFILE) { - rc = ad_read(ad, name); + rc = ad_read(ad, fsp->base_fsp->fsp_name->base_name); if (rc == -1) { goto exit; } @@ -3597,14 +3552,12 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, if ((len + offset) > ad_getentrylen(ad, ADEID_RFORK)) { ad_setentrylen(ad, ADEID_RFORK, len + offset); - rc = ad_write(ad, name); + rc = ad_write(ad, fsp->base_fsp->fsp_name->base_name); } } } exit: - fsp->base_fsp->fsp_name->base_name = tmp_base_name; - TALLOC_FREE(name); TALLOC_FREE(ai); if (rc != 0) { return -1; @@ -3948,38 +3901,12 @@ static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { int rc; - char *name = NULL; - char *tmp_base_name = NULL; - NTSTATUS status; struct adouble *ad = (struct adouble *) VFS_FETCH_FSP_EXTENSION(handle, fsp); DEBUG(10, ("fruit_fstat called for %s\n", smb_fname_str_dbg(fsp->fsp_name))); - 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 (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; - } - if (ad == NULL || fsp->base_fsp == NULL) { rc = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); goto exit; @@ -4014,10 +3941,6 @@ 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; } -- 2.9.3 From a70610d85e020221bd602e64b523c353028a5cc4 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 11:08:53 +0100 Subject: [PATCH 36/60] vfs_fruit: fix fruit_check_access() Applying fcntl read locks requires an fd opened for reading. This means we have to check the open flags of an fd and if the fd is not opened for reading, we can't use it to set shared fctnl locks. Iow we won't be applying interop locks with Netatalk for files openend write-only. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 41a2b2f5cdf751e17bde60e5cfbe395450e67485) --- source3/modules/vfs_fruit.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 59e7862..8a448fa 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -1805,6 +1805,8 @@ 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; @@ -1816,6 +1818,26 @@ 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 */ @@ -1837,7 +1859,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, } /* Set locks */ - if (access_mask & FILE_READ_DATA) { + if ((access_mask & FILE_READ_DATA) && have_read) { off = access_to_netatalk_brl(fork_type, FILE_READ_DATA); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -1851,7 +1873,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, TALLOC_FREE(br_lck); } - if (deny_mode & DENY_READ) { + if ((deny_mode & DENY_READ) && have_read) { off = denymode_to_netatalk_brl(fork_type, DENY_READ); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -1887,7 +1909,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, } /* Set locks */ - if (access_mask & FILE_WRITE_DATA) { + if ((access_mask & FILE_WRITE_DATA) && have_read) { off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, @@ -1901,7 +1923,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, TALLOC_FREE(br_lck); } - if (deny_mode & DENY_WRITE) { + if ((deny_mode & DENY_WRITE) && have_read) { off = denymode_to_netatalk_brl(fork_type, DENY_WRITE); br_lck = do_lock( handle->conn->sconn->msg_ctx, fsp, -- 2.9.3 From 734c116f6076e65029bcc100f9b3898de90678c7 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 22:54:46 +0100 Subject: [PATCH 37/60] selftest: disable vfs_fruit tests The next commits will completely change handle based VFS ops. This couldn't be done in a piecemeal fashion, I had to wipe the slate clean. Disabling tests in order to not break git bisects. Tests will be reenabled after a few commits that apply the larger change in a somewhat digestible fashion. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 8703b8ef9d54c841d9da3f94b81195f247873dea) --- source3/selftest/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 4ca064a..705874d 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -329,7 +329,7 @@ nbt = ["nbt.dgram" ] libsmbclient = ["libsmbclient"] -vfs = ["vfs.fruit", "vfs.acl_xattr"] +vfs = ["vfs.acl_xattr"] tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs -- 2.9.3 From ba784b56c8dfa88c71062bb6587040f44771edb1 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 19:12:32 +0100 Subject: [PATCH 38/60] vfs_fruit: rework struct adouble API o factor out ad_open(), opens an fd to be used with IO on the metadata streams o rename ad_write() to ad_set() as this aligns nicely with the existing ad_get. This is the pathname based version used to solely set metadata on a file, there's also a handle based version: o add ad_fset(), a handle based version that can be used to set metadata and to update the AppleDouble header in a ._ AppleDouble file o remove fruit_fsp_recheck(), looking at it more closely, it is not needed This commit *compiles*, but all callers in the VFS ops must now be updated to use the new semantics, this comes next... BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 1d1203574328570288806fffefabb550ecc4e95d) --- source3/modules/vfs_fruit.c | 713 ++++++++++++++++++++++++++------------------ 1 file changed, 423 insertions(+), 290 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 8a448fa..6bdde6e 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -349,7 +349,8 @@ struct ad_entry { struct adouble { vfs_handle_struct *ad_handle; - files_struct *ad_fsp; + int ad_fd; + bool ad_opened; adouble_type_t ad_type; uint32_t ad_magic; uint32_t ad_version; @@ -402,12 +403,21 @@ 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, files_struct *fsp); -static int ad_write(struct adouble *ad, const char *path); + adouble_type_t type); +static int ad_set(struct adouble *ad, const char *path); +static int ad_fset(struct adouble *ad, files_struct *fsp); static int adouble_path(TALLOC_CTX *ctx, const char *path_in, char **path_out); /** @@ -769,7 +779,7 @@ exit: /** * Read and parse Netatalk AppleDouble metadata xattr **/ -static ssize_t ad_header_read_meta(struct adouble *ad, const char *path) +static ssize_t ad_read_meta(struct adouble *ad, const char *path) { int rc = 0; ssize_t ealen; @@ -841,196 +851,220 @@ exit: return ealen; } -/** - * Read and parse resource fork, either ._ AppleDouble file or xattr - **/ -static ssize_t ad_header_read_rsrc(struct adouble *ad, const char *path) +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) { struct fruit_config_data *config = NULL; - 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; + int fd; - SMB_VFS_HANDLE_GET_DATA(ad->ad_handle, config, + SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - /* Try rw first so we can use the fd in ad_convert() */ - mode = O_RDWR; - - if (ad->ad_fsp && ad->ad_fsp->fh && (ad->ad_fsp->fh->fd != -1)) { - fd = ad->ad_fsp->fh->fd; + if (config->rsrc == FRUIT_RSRC_XATTR) { + fd = ad_open_rsrc_xattr(path, flags, mode); } else { - 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; - } - } + fd = ad_open_rsrc_adouble(path, flags, mode); + } - 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); - } + return fd; +} - 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; +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"); + + if (t == ADOUBLE_META) { + fd = ad_open_meta(path, flags, mode); + } else { + fd = ad_open_rsrc(handle, path, flags, mode); } - if (config->rsrc == FRUIT_RSRC_XATTR) { - /* FIXME: direct sys_fstat(), don't have an fsp */ - rc = sys_fstat( - fd, &sbuf, + 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 (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; - } + if (ret != 0) { + 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; - } + ad_setentrylen(ad, ADEID_RFORK, st.st_ex_size); + return st.st_ex_size; +} - /* Now parse entries */ - ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size); - if (!ok) { - DEBUG(1, ("invalid AppleDouble resource %s\n", path)); - errno = EINVAL; - rc = -1; - 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; - 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 resource %s\n", path)); - errno = EINVAL; - rc = -1; - goto exit; - } + 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 ((mode == O_RDWR) - && (ad_getentrylen(ad, ADEID_FINDERI) > ADEDLEN_FINDERI)) { - char *p_ad = NULL; - char *p_meta_ad = NULL; + ret = sys_fstat(ad->ad_fd, &sbuf, lp_fake_directory_create_times( + SNUM(ad->ad_handle->conn))); + if (ret != 0) { + return -1; + } - 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; - } + /* 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; + } - meta_ad = ad_init(talloc_tos(), ad->ad_handle, - ADOUBLE_META, NULL); - if (meta_ad == NULL) { - rc = -1; - 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; + } - p_ad = ad_get_entry(ad, ADEID_FINDERI); - if (p_ad == NULL) { - rc = -1; - goto exit; - } - p_meta_ad = ad_get_entry(meta_ad, ADEID_FINDERI); - if (p_meta_ad == NULL) { - rc = -1; - goto exit; - } + if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) { + return len; + } - memcpy(p_meta_ad, p_ad, ADEDLEN_FINDERI); + /* + * 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. + */ - rc = ad_write(meta_ad, path); - if (rc != 0) { - rc = -1; - goto exit; - } - } + ret = ad_convert(ad, ad->ad_fd); + if (ret != 0) { + DBG_WARNING("Failed to convert [%s]\n", path); + return len; } - DEBUG(10, ("opened AppleDouble: %s\n", path)); + ok = ad_pack(ad); + if (!ok) { + DBG_WARNING("ad_pack [%s] failed\n", path); + return -1; + } -exit: - if (rc != 0) { - saved_errno = errno; - len = -1; + 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; } - if (opened && fd != -1) { - close(fd); + + meta_ad = ad_init(talloc_tos(), ad->ad_handle, ADOUBLE_META); + if (meta_ad == NULL) { + return -1; } - TALLOC_FREE(adpath); + + p_ad = ad_get_entry(ad, ADEID_FINDERI); + if (p_ad == NULL) { + TALLOC_FREE(meta_ad); + return -1; + } + p_meta_ad = ad_get_entry(meta_ad, ADEID_FINDERI); + if (p_meta_ad == NULL) { + TALLOC_FREE(meta_ad); + return -1; + } + + memcpy(p_meta_ad, p_ad, ADEDLEN_FINDERI); + + ret = ad_set(meta_ad, path); TALLOC_FREE(meta_ad); - if (rc != 0) { - errno = saved_errno; + 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); + } + return len; } @@ -1041,14 +1075,23 @@ static ssize_t ad_read(struct adouble *ad, const char *path) { switch (ad->ad_type) { case ADOUBLE_META: - return ad_header_read_meta(ad, path); + return ad_read_meta(ad, path); case ADOUBLE_RSRC: - return ad_header_read_rsrc(ad, path); + return ad_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 * @@ -1058,14 +1101,11 @@ static ssize_t ad_read(struct adouble *ad, const char *path) * @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, files_struct *fsp) + adouble_type_t type) { int rc = 0; size_t adsize = 0; @@ -1088,39 +1128,27 @@ static struct adouble *ad_alloc(TALLOC_CTX *ctx, vfs_handle_struct *handle, return 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) { + 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) { 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) { @@ -1135,12 +1163,11 @@ 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, files_struct *fsp) + adouble_type_t type) { int rc = 0; const struct ad_entry_order *eid; @@ -1166,7 +1193,7 @@ static struct adouble *ad_init(TALLOC_CTX *ctx, vfs_handle_struct *handle, return NULL; } - ad = ad_alloc(ctx, handle, type, fsp); + ad = ad_alloc(ctx, handle, type); if (ad == NULL) { return NULL; } @@ -1205,16 +1232,42 @@ 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, NULL); + ad = ad_alloc(ctx, handle, type); 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)); @@ -1233,21 +1286,144 @@ exit: } /** + * Return AppleDouble data for a file + * + * @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 + * + * @return talloced struct adouble or NULL on error + **/ +static struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle, + files_struct *fsp, adouble_type_t type) +{ + 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)); + + ad = ad_alloc(ctx, handle, type); + if (ad == NULL) { + rc = -1; + goto exit; + } + + 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; + } + } + } + + 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; + } - * @param[in] path pathname to file or directory, may be NULL for a - * resource fork + 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_write(struct adouble *ad, const char *path) +static int ad_fset(struct adouble *ad, files_struct *fsp) { - int rc = 0; + 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; @@ -1255,31 +1431,32 @@ static int ad_write(struct adouble *ad, const char *path) 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); + rc = SMB_VFS_NEXT_FSETXATTR(ad->ad_handle, + fsp, + 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; + 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; } -exit: + + DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc); + return rc; } @@ -1537,19 +1714,6 @@ 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, @@ -2577,29 +2741,22 @@ 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(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), - handle, ADOUBLE_META, fsp); + ad = ad_init(fsp, handle, ADOUBLE_META); if (ad == NULL) { rc = -1; goto exit; } - rc = ad_write(ad, smb_fname->base_name); + fsp->fh->fd = hostfd; + + rc = ad_fset(ad, fsp); + fsp->fh->fd = -1; if (rc != 0) { rc = -1; goto exit; } - } 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; - } + + TALLOC_FREE(ad); } exit: @@ -2714,28 +2871,21 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, fsp->fh->fd = hostfd; if (flags & (O_CREAT | O_TRUNC)) { - ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), - handle, ADOUBLE_RSRC, fsp); + ad = ad_init(fsp, handle, ADOUBLE_RSRC); if (ad == NULL) { rc = -1; goto exit; } - rc = ad_write(ad, smb_fname->base_name); + + fsp->fh->fd = hostfd; + + rc = ad_fset(ad, fsp); + fsp->fh->fd = -1; if (rc != 0) { rc = -1; goto exit; } - } 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; - } + TALLOC_FREE(ad); } exit: @@ -3399,11 +3549,6 @@ static ssize_t fruit_pread(vfs_handle_struct *handle, goto exit; } - if (!fruit_fsp_recheck(ad, fsp)) { - rc = -1; - goto exit; - } - if (ad->ad_type == ADOUBLE_META) { char afpinfo_buf[AFP_INFO_SIZE]; char *p = NULL; @@ -3539,11 +3684,6 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, goto exit; } - if (!fruit_fsp_recheck(ad, fsp)) { - rc = -1; - goto exit; - } - if (ad->ad_type == ADOUBLE_META) { char *p = NULL; @@ -3556,7 +3696,7 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, } memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - rc = ad_write(ad, fsp->base_fsp->fsp_name->base_name); + rc = ad_fset(ad, fsp); } else { len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset + ad_getentryoff(ad, ADEID_RFORK)); @@ -3574,7 +3714,7 @@ static ssize_t fruit_pwrite(vfs_handle_struct *handle, if ((len + offset) > ad_getentrylen(ad, ADEID_RFORK)) { ad_setentrylen(ad, ADEID_RFORK, len + offset); - rc = ad_write(ad, fsp->base_fsp->fsp_name->base_name); + rc = ad_fset(ad, fsp); } } } @@ -3934,11 +4074,6 @@ static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp, goto exit; } - if (!fruit_fsp_recheck(ad, fsp)) { - rc = -1; - goto exit; - } - switch (ad->ad_type) { case ADOUBLE_META: rc = fruit_fstat_meta(handle, fsp, sbuf); @@ -4250,7 +4385,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_write(ad, smb_fname->base_name); + rc = ad_set(ad, smb_fname->base_name); exit: @@ -4275,10 +4410,6 @@ static int fruit_fallocate(struct vfs_handle_struct *handle, 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; @@ -4303,14 +4434,16 @@ static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, off_t offset) { int rc; - struct adouble *ad = - (struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp); - off_t ad_off = ad_getentryoff(ad, ADEID_RFORK); + struct adouble *ad = NULL; + off_t ad_off; - if (!fruit_fsp_recheck(ad, fsp)) { + ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC); + if (ad == NULL) { return -1; } + ad_off = ad_getentryoff(ad, ADEID_RFORK); + rc = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset + ad_off); if (rc != 0) { return -1; @@ -4318,7 +4451,7 @@ static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, ad_setentrylen(ad, ADEID_RFORK, offset); - rc = ad_write(ad, NULL); + rc = ad_fset(ad, fsp); if (rc != 0) { DBG_ERR("ad_write [%s] failed [%s]\n", fsp_str_dbg(fsp), strerror(errno)); -- 2.9.3 From 4eae7852da8dd1ca11110114b96ee678f5651630 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:34:55 +0100 Subject: [PATCH 39/60] vfs_fruit: refactor fruit_open and use new adouble API Use struct fio to denote a fsp handle is for a stream we care about. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 6537c56de5dae8a1d193a949910296aea1cb6a4e) --- source3/modules/vfs_fruit.c | 65 ++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 6bdde6e..3443c81 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2693,6 +2693,8 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle, int hostfd = -1; struct adouble *ad = NULL; + DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname)); + /* Create an smb_filename with stream_name == NULL. */ smb_fname_base = synthetic_smb_fname(talloc_tos(), smb_fname->base_name, @@ -2782,8 +2784,9 @@ static int fruit_open_meta(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) { - int rc; + int fd; struct fruit_config_data *config = NULL; + struct fio *fio = NULL; DBG_DEBUG("path [%s]\n", smb_fname_str_dbg(smb_fname)); @@ -2792,12 +2795,12 @@ static int fruit_open_meta(vfs_handle_struct *handle, switch (config->meta) { case FRUIT_META_STREAM: - rc = fruit_open_meta_stream(handle, smb_fname, + fd = fruit_open_meta_stream(handle, smb_fname, fsp, flags, mode); break; case FRUIT_META_NETATALK: - rc = fruit_open_meta_netatalk(handle, smb_fname, + fd = fruit_open_meta_netatalk(handle, smb_fname, fsp, flags, mode); break; @@ -2806,8 +2809,17 @@ static int fruit_open_meta(vfs_handle_struct *handle, return -1; } - DBG_DEBUG("path [%s] rc [%d]\n", smb_fname_str_dbg(smb_fname), rc); - return rc; + 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, @@ -2819,9 +2831,13 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, int rc = 0; struct adouble *ad = NULL; struct smb_filename *smb_fname_base = NULL; + struct fruit_config_data *config = NULL; char *adpath = NULL; int hostfd = -1; + SMB_VFS_HANDLE_GET_DATA(handle, config, + struct fruit_config_data, return -1); + if (!(flags & O_CREAT) && !VALID_STAT(smb_fname->st)) { rc = SMB_VFS_NEXT_STAT(handle, smb_fname); if (rc != 0) { @@ -2867,9 +2883,6 @@ 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); if (ad == NULL) { @@ -2919,16 +2932,11 @@ static int fruit_open_rsrc_xattr(vfs_handle_struct *handle, { #ifdef HAVE_ATTROPEN int fd = -1; - struct adouble *ad = NULL; - - ad = ad_init(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), - handle, ADOUBLE_RSRC, fsp); - if (ad == NULL) { - return -1; - } fd = attropen(smb_fname->base_name, - AFPRESOURCE_EA_NETATALK, flags, mode); + AFPRESOURCE_EA_NETATALK, + flags, + mode); if (fd == -1) { return -1; } @@ -2947,6 +2955,7 @@ static int fruit_open_rsrc(vfs_handle_struct *handle, { int fd; struct fruit_config_data *config = NULL; + struct fio *fio = NULL; DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname)); @@ -2974,6 +2983,15 @@ static int fruit_open_rsrc(vfs_handle_struct *handle, } 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; } @@ -2981,20 +2999,25 @@ static int fruit_open(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) { - DEBUG(10, ("fruit_open called for %s\n", - smb_fname_str_dbg(smb_fname))); + int fd; + + DBG_DEBUG("Path [%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)) { - return fruit_open_meta(handle, smb_fname, fsp, flags, mode); + fd = fruit_open_meta(handle, smb_fname, fsp, flags, mode); } else if (is_afpresource_stream(smb_fname)) { - return fruit_open_rsrc(handle, smb_fname, fsp, flags, mode); + fd = fruit_open_rsrc(handle, smb_fname, fsp, flags, mode); + } else { + fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); } - return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); + DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd); + + return fd; } static int fruit_rename(struct vfs_handle_struct *handle, -- 2.9.3 From 244ba3ae497e012e5c1825d38caeeb7f48a1c89f Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:38:17 +0100 Subject: [PATCH 40/60] vfs_fruit: refactor fruit_pread and fruit_pwrite and use new adouble API Use struct fio to denote a fsp handle is for a stream we care about. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit fcb9c840d7d082457c3136a44a23b489c98b0327) --- source3/modules/vfs_fruit.c | 524 +++++++++++++++++++++++++++++--------------- 1 file changed, 349 insertions(+), 175 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 3443c81..86f0859 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3523,233 +3523,407 @@ exit_rmdir: return SMB_VFS_NEXT_RMDIR(handle, smb_fname); } -static ssize_t fruit_pread(vfs_handle_struct *handle, - files_struct *fsp, void *data, - size_t n, off_t offset) +static ssize_t fruit_pread_meta_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_meta_adouble(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; - ssize_t len = -1; - size_t to_return = n; + struct adouble *ad = NULL; + char afpinfo_buf[AFP_INFO_SIZE]; + char *p = NULL; + ssize_t nread; - DEBUG(10, ("fruit_pread: offset=%d, size=%d\n", (int)offset, (int)n)); + ai = afpinfo_new(talloc_tos()); + if (ai == NULL) { + return -1; + } - if (!fsp->base_fsp) { - return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); + ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META); + if (ad == NULL) { + nread = -1; + goto fail; } - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct fruit_config_data, return -1); + 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; + } - if (is_afpinfo_stream(fsp->fsp_name)) { - /* - * 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; - } + memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI); + + nread = afpinfo_pack(ai, afpinfo_buf); + if (nread != AFP_INFO_SIZE) { + nread = -1; + goto fail; + } - to_return = MIN(n, AFP_INFO_SIZE); + memcpy(data, afpinfo_buf, n); + nread = n; - /* Yes, macOS always reads from offset 0 */ - offset = 0; +fail: + TALLOC_FREE(ai); + return nread; +} + +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; + + /* + * 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; + } + + /* 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; + + default: + DBG_ERR("Unexpected meta config [%d]\n", fio->config->meta); + return -1; } + 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) { - len = SMB_VFS_NEXT_PREAD(handle, fsp, data, to_return, offset); - if (len == -1) { - rc = -1; - goto exit; - } - goto exit; + return -1; } - if (ad->ad_type == ADOUBLE_META) { - char afpinfo_buf[AFP_INFO_SIZE]; - char *p = NULL; + nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, + offset + ad_getentryoff(ad, ADEID_RFORK)); - ai = afpinfo_new(talloc_tos()); - if (ai == NULL) { - rc = -1; - goto exit; - } + TALLOC_FREE(ad); + return nread; +} - len = ad_read(ad, fsp->base_fsp->fsp_name->base_name); - if (len == -1) { - rc = -1; - goto exit; - } +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; - p = ad_get_entry(ad, ADEID_FINDERI); - if (p == NULL) { - DBG_ERR("No ADEID_FINDERI for [%s]\n", - fsp->fsp_name->base_name); - rc = -1; - goto exit; - } + switch (fio->config->rsrc) { + case FRUIT_RSRC_STREAM: + nread = fruit_pread_rsrc_stream(handle, fsp, data, n, offset); + break; - memcpy(&ai->afpi_FinderInfo[0], p, ADEDLEN_FINDERI); + case FRUIT_RSRC_ADFILE: + nread = fruit_pread_rsrc_adouble(handle, fsp, data, n, offset); + break; - len = afpinfo_pack(ai, afpinfo_buf); - if (len != AFP_INFO_SIZE) { - rc = -1; - goto exit; - } + case FRUIT_RSRC_XATTR: + nread = fruit_pread_rsrc_xattr(handle, fsp, data, n, offset); + break; - /* - * 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; - } + default: + DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc); + return -1; } -exit: - TALLOC_FREE(ai); - if (rc != 0) { - len = -1; + + return nread; +} + +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); } - DEBUG(10, ("fruit_pread: rc=%d, len=%zd\n", rc, len)); - return len; + + if (fio->type == ADOUBLE_META) { + nread = fruit_pread_meta(handle, fsp, data, n, offset); + } else { + nread = fruit_pread_rsrc(handle, fsp, data, n, offset); + } + + DBG_DEBUG("Path [%s] nread [%zd]\n", fsp_str_dbg(fsp), nread); + return nread; } -static ssize_t fruit_pwrite(vfs_handle_struct *handle, - files_struct *fsp, const void *data, - size_t n, off_t offset) +static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle, + files_struct *fsp, const 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; - ssize_t len; + int ret; - DEBUG(10, ("fruit_pwrite: offset=%d, size=%d\n", (int)offset, (int)n)); + ai = afpinfo_unpack(talloc_tos(), data); + if (ai == NULL) { + return -1; + } - if (!fsp->base_fsp) { - return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); + 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; + } + + return n; } - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct fruit_config_data, return -1); + return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); +} - if (is_afpinfo_stream(fsp->fsp_name)) { - /* - * 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) { - 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; - } +static ssize_t fruit_pwrite_meta_netatalk(vfs_handle_struct *handle, + files_struct *fsp, const void *data, + size_t n, off_t offset) +{ + struct adouble *ad = NULL; + AfpInfo *ai = NULL; + char *p = NULL; + int ret; - if (ai_empty_finderinfo(ai)) { - switch (config->meta) { - case FRUIT_META_STREAM: - rc = SMB_VFS_UNLINK(handle->conn, fsp->fsp_name); - break; - - case FRUIT_META_NETATALK: - rc = SMB_VFS_REMOVEXATTR( - handle->conn, - fsp->fsp_name->base_name, - AFPINFO_EA_NETATALK); - break; - - default: - DBG_ERR("Unexpected meta config [%d]\n", - config->meta); - rc = -1; - goto exit; - } + ai = afpinfo_unpack(talloc_tos(), data); + if (ai == NULL) { + return -1; + } - 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; - } + if (ai_empty_finderinfo(ai)) { + ret = SMB_VFS_REMOVEXATTR(handle->conn, + fsp->fsp_name->base_name, + AFPINFO_EA_NETATALK); - rc = 0; - goto exit; + 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; } + + return n; } + ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META); if (ad == NULL) { - len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset); - if (len != n) { - rc = -1; - goto exit; + ad = ad_init(talloc_tos(), handle, ADOUBLE_META); + if (ad == NULL) { + return -1; } - 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; } - if (ad->ad_type == ADOUBLE_META) { - char *p = NULL; + memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - p = ad_get_entry(ad, ADEID_FINDERI); - if (p == NULL) { - DBG_ERR("No ADEID_FINDERI for [%s]\n", - fsp->fsp_name->base_name); - rc = -1; - goto exit; - } + ret = ad_fset(ad, fsp); + if (ret != 0) { + DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp)); + TALLOC_FREE(ad); + return -1; + } - memcpy(p, &ai->afpi_FinderInfo[0], ADEDLEN_FINDERI); - rc = ad_fset(ad, fsp); - } else { - len = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, - offset + ad_getentryoff(ad, ADEID_RFORK)); - if (len != n) { - rc = -1; - goto exit; - } + TALLOC_FREE(ad); + return n; +} - if (config->rsrc == FRUIT_RSRC_ADFILE) { - rc = ad_read(ad, fsp->base_fsp->fsp_name->base_name); - if (rc == -1) { - goto exit; - } - rc = 0; +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; - if ((len + offset) > ad_getentrylen(ad, ADEID_RFORK)) { - ad_setentrylen(ad, ADEID_RFORK, len + offset); - rc = ad_fset(ad, fsp); - } - } + /* + * 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; } -exit: - TALLOC_FREE(ai); - if (rc != 0) { + 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; + } + + 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; } + + 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 ((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; + } + } + + 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); + 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; +} + /** * Helper to stat/lstat the base file of an smb_fname. */ -- 2.9.3 From 3ce3ae984496a589abc78f32501c431dff68392b Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:39:38 +0100 Subject: [PATCH 41/60] vfs_fruit: refactor fruit_fstat and use new adouble API Use struct fio to denote a fsp handle is for a stream we care about. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit ae6199c5ef9022518a709bb9aff20b8b2d83e456) --- source3/modules/vfs_fruit.c | 153 ++++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 47 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 86f0859..9a4babe 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4206,17 +4206,24 @@ static int fruit_lstat(vfs_handle_struct *handle, return rc; } -static int fruit_fstat_meta(vfs_handle_struct *handle, - files_struct *fsp, - SMB_STRUCT_STAT *sbuf) +static int fruit_fstat_meta_stream(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))); + return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); +} - /* Populate the stat struct with info from the base file. */ - if (fruit_stat_base(handle, fsp->base_fsp->fsp_name, false) == -1) { +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); @@ -4224,65 +4231,119 @@ static int fruit_fstat_meta(vfs_handle_struct *handle, return 0; } -static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp, - SMB_STRUCT_STAT *sbuf) +static int fruit_fstat_meta(vfs_handle_struct *handle, + files_struct *fsp, + SMB_STRUCT_STAT *sbuf, + struct fio *fio) { - struct fruit_config_data *config; - struct adouble *ad = (struct adouble *)VFS_FETCH_FSP_EXTENSION( - handle, fsp); + int ret; - DEBUG(10, ("fruit_fstat_rsrc called for %s\n", - smb_fname_str_dbg(fsp->base_fsp->fsp_name))); + DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp)); - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct fruit_config_data, return -1); + switch (fio->config->meta) { + case FRUIT_META_STREAM: + ret = fruit_fstat_meta_stream(handle, fsp, sbuf); + break; - if (config->rsrc == FRUIT_RSRC_STREAM) { - return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + 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. */ - if (fruit_stat_base(handle, fsp->base_fsp->fsp_name, false) == -1) { + 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); - DEBUG(10, ("fruit_fstat_rsrc %s, size: %zd\n", - smb_fname_str_dbg(fsp->fsp_name), - (ssize_t)sbuf->st_ex_size)); - + TALLOC_FREE(ad); return 0; } +static int fruit_fstat_rsrc(vfs_handle_struct *handle, files_struct *fsp, + SMB_STRUCT_STAT *sbuf, struct fio *fio) +{ + 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; - struct adouble *ad = (struct adouble *) - VFS_FETCH_FSP_EXTENSION(handle, fsp); - DEBUG(10, ("fruit_fstat called for %s\n", - smb_fname_str_dbg(fsp->fsp_name))); - - if (ad == NULL || fsp->base_fsp == NULL) { - rc = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); - goto exit; + if (fio == NULL) { + return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); } - switch (ad->ad_type) { - case ADOUBLE_META: - rc = fruit_fstat_meta(handle, fsp, sbuf); - break; - case ADOUBLE_RSRC: - rc = fruit_fstat_rsrc(handle, fsp, sbuf); - break; - default: - DEBUG(10, ("fruit_fstat %s: bad type\n", - smb_fname_str_dbg(fsp->fsp_name))); - rc = -1; - goto exit; + DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp)); + + if (fio->type == ADOUBLE_META) { + rc = fruit_fstat_meta(handle, fsp, sbuf, fio); + } else { + rc = fruit_fstat_rsrc(handle, fsp, sbuf, fio); } if (rc == 0) { @@ -4291,10 +4352,8 @@ static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp, 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)); + DBG_DEBUG("Path [%s] rc [%d] size [%zd]\n", + fsp_str_dbg(fsp), rc, sbuf->st_ex_size); return rc; } -- 2.9.3 From bff504def5c0a9a86b79bcde1cad1413569b70b5 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:41:55 +0100 Subject: [PATCH 42/60] vfs_fruit: use fio in fruit_fallocate BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b3c0f785d753b26404f67acf8061be1cafde79a9) --- source3/modules/vfs_fruit.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 9a4babe..c4f73bb 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4659,10 +4659,9 @@ static int fruit_fallocate(struct vfs_handle_struct *handle, off_t offset, off_t len) { - struct adouble *ad = - (struct adouble *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); - if (ad == NULL) { + if (fio == NULL) { return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len); } -- 2.9.3 From 9a9d82f7bc68a5a8ba0f7a83421310e0ca0f9c03 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:42:54 +0100 Subject: [PATCH 43/60] vfs_fruit: refactor fruit_ftruncate and use new adouble API Use struct fio to denote a fsp handle is for a stream we care about. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit cc88132854ed47510e056ed451ed376770ee301e) --- source3/modules/vfs_fruit.c | 65 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index c4f73bb..981f950 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4694,6 +4694,8 @@ static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, 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; } @@ -4701,6 +4703,7 @@ static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, rc = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset + ad_off); if (rc != 0) { + TALLOC_FREE(ad); return -1; } @@ -4708,14 +4711,13 @@ static int fruit_ftruncate_rsrc_adouble(struct vfs_handle_struct *handle, rc = ad_fset(ad, fsp); if (rc != 0) { - DBG_ERR("ad_write [%s] failed [%s]\n", + DBG_ERR("ad_fset [%s] failed [%s]\n", fsp_str_dbg(fsp), strerror(errno)); + TALLOC_FREE(ad); return -1; } - DBG_DEBUG("Path [%s] offset [%jd]\n", - fsp_str_dbg(fsp), (intmax_t)offset); - + TALLOC_FREE(ad); return 0; } @@ -4734,13 +4736,10 @@ static int fruit_ftruncate_rsrc(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; - struct fruit_config_data *config; - - SMB_VFS_HANDLE_GET_DATA(handle, config, - struct fruit_config_data, return -1); - switch (config->rsrc) { + switch (fio->config->rsrc) { case FRUIT_RSRC_XATTR: ret = fruit_ftruncate_rsrc_xattr(handle, fsp, offset); break; @@ -4754,7 +4753,7 @@ static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle, break; default: - DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc); + DBG_ERR("Unexpected rsrc config [%d]\n", fio->config->rsrc); return -1; } @@ -4762,33 +4761,45 @@ static int fruit_ftruncate_rsrc(struct vfs_handle_struct *handle, 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; + } + + /* OS X returns success but does nothing */ + DBG_INFO("ignoring ftruncate %s to %jd\n", + fsp_str_dbg(fsp), (intmax_t)offset); + return 0; +} + static int fruit_ftruncate(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t offset) { - DBG_DEBUG("fruit_ftruncate called for file %s offset %.0f\n", - fsp_str_dbg(fsp), (double)offset); + struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + int ret; - if (is_afpinfo_stream(fsp->fsp_name)) { - 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; - } + DBG_DEBUG("Path [%s] offset [%zd]\n", fsp_str_dbg(fsp), offset); - DBG_WARNING("ignoring ftruncate %s to %jd", - fsp_str_dbg(fsp), (intmax_t)offset); - /* OS X returns success but does nothing */ - return 0; + if (fio == NULL) { + return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); } - if (is_afpresource_stream(fsp->fsp_name)) { - return fruit_ftruncate_rsrc(handle, fsp, offset); + if (fio->type == ADOUBLE_META) { + ret = fruit_ftruncate_meta(handle, fsp, offset); + } else { + ret = fruit_ftruncate_rsrc(handle, fsp, offset); } - return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset); + DBG_DEBUG("Path [%s] result [%d]\n", fsp_str_dbg(fsp), ret); + return ret; } static NTSTATUS fruit_create_file(vfs_handle_struct *handle, -- 2.9.3 From baee4749c37a6c3fa89377728fc3b2b1836ff7cb Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 20:43:21 +0100 Subject: [PATCH 44/60] selftest: reenable vfs_fruit tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 51189bd4758a140bad6abf3300c931302432a687) --- source3/selftest/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 705874d..4ca064a 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -329,7 +329,7 @@ nbt = ["nbt.dgram" ] libsmbclient = ["libsmbclient"] -vfs = ["vfs.acl_xattr"] +vfs = ["vfs.fruit", "vfs.acl_xattr"] tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs -- 2.9.3 From b25c3ab599821e00a4323067410b9f22fc56d78f Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 15 Nov 2016 22:31:20 +0100 Subject: [PATCH 45/60] selftest: move vfs_fruit tests that require "fruit:metadata=netatalk" to vfs.fruit_netatalk BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit cc885223d79a7e8eb2177a351b745dceec0c9f5a) --- source3/selftest/tests.py | 4 +++- source4/torture/vfs/fruit.c | 15 +++++++++++++-- source4/torture/vfs/vfs.c | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 4ca064a..03341d3 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -329,7 +329,7 @@ nbt = ["nbt.dgram" ] libsmbclient = ["libsmbclient"] -vfs = ["vfs.fruit", "vfs.acl_xattr"] +vfs = ["vfs.fruit", "vfs.acl_xattr", "vfs.fruit_netatalk"] tests= base + raw + smb2 + rpc + unix + local + rap + nbt + libsmbclient + idmap + vfs @@ -413,6 +413,8 @@ for t in tests: 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') + elif t == "vfs.fruit_netatalk": + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_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 d5de9d5..ff3bfa2 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3542,11 +3542,9 @@ 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); @@ -3563,3 +3561,16 @@ struct torture_suite *torture_vfs_fruit(void) 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 7f805f4..8b443fb 100644 --- a/source4/torture/vfs/vfs.c +++ b/source4/torture/vfs/vfs.c @@ -107,6 +107,7 @@ 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); -- 2.9.3 From 9db7e09c0f08a22d92a5c1efd6a91f978ee4c422 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 15 Nov 2016 15:25:14 +0100 Subject: [PATCH 46/60] selftest: run vfs_fruit tests against share with fruit:metadata=stream BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit d9ab40e0834c074ea26460347b035c52eb5eb0d7) --- selftest/target/Samba3.pm | 7 +++++++ source3/selftest/tests.py | 1 + 2 files changed, 8 insertions(+) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index f05eb16..330dbef 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1661,6 +1661,13 @@ sub provision($$$$$$$$) 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 + [badname-tmp] path = $badnames_shrdir guest ok = yes diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 03341d3..bcbee6c 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -413,6 +413,7 @@ for t in tests: 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') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream -U$USERNAME%$PASSWORD') elif t == "vfs.fruit_netatalk": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') elif t == "rpc.schannel_anon_setpw": -- 2.9.3 From 709f224c8c118de961934e92b1bf8c5c44c8e8e4 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 07:42:07 +0100 Subject: [PATCH 47/60] selftest: also run vfs_fruit tests with streams_depot BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit f7b0982826b58cfcdaf8782e15c2440f31a45ba2) --- selftest/target/Samba3.pm | 7 +++++++ source3/selftest/tests.py | 1 + 2 files changed, 8 insertions(+) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 330dbef..9db578d 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1668,6 +1668,13 @@ sub provision($$$$$$$$) 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 + [badname-tmp] path = $badnames_shrdir guest ok = yes diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index bcbee6c..8bb79be 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -414,6 +414,7 @@ for t in tests: elif t == "vfs.fruit": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_stream_depot -U$USERNAME%$PASSWORD') elif t == "vfs.fruit_netatalk": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') elif t == "rpc.schannel_anon_setpw": -- 2.9.3 From 4a38883d1b492f71385ab40e885523879c8fd5d1 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 17:41:14 +0100 Subject: [PATCH 48/60] selftest: add description to vfs_fruit testsuites BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 9975c7569cf5af74c25ac03985a7c409164ac2ce) --- source3/selftest/tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 8bb79be..f537f10 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -412,9 +412,9 @@ 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') - plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream -U$USERNAME%$PASSWORD') - plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_stream_depot -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share', 'metadata_netatalk') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream -U$USERNAME%$PASSWORD', 'metadata_stream') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_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') elif t == "rpc.schannel_anon_setpw": -- 2.9.3 From 13d7a81dad8fb5f903c6bad8d25ff8405c164f77 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 29 Nov 2016 16:21:08 +0100 Subject: [PATCH 49/60] s4/torture: vfs_fruit: add test_null_afpinfo test BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 3227b891fcdd912b0c09398fed751fe8b53d01c9) --- source4/torture/vfs/fruit.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index ff3bfa2..27d6065 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3527,6 +3527,91 @@ 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; +} + +/* * 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: @@ -3558,6 +3643,7 @@ 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); return suite; } -- 2.9.3 From ed016e7aad2f8a81cc6861f2eab5c5bcb06c68e9 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 5 Dec 2016 11:21:15 +0100 Subject: [PATCH 50/60] s4/torture: vfs_fruit: test deleting a file with resource fork All the other tests ignore the return value of smb2_util_unlink(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit f555c2318eb06d1ceef32423dba9cd1a7c76f956) --- source4/torture/vfs/fruit.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 27d6065..2167032 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3611,6 +3611,38 @@ done: 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; +} + /* * 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 @@ -3644,6 +3676,7 @@ struct torture_suite *torture_vfs_fruit(void) 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); return suite; } -- 2.9.3 From dedc8357fdf552c397e532dd160532ecbcfb7c96 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 6 Dec 2016 10:25:46 +0100 Subject: [PATCH 51/60] s4/torture: add a vfs_fruit renaming test with open rsrc fork Verify IO on the resource fork works after a rename of the basefile. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 8ae4539e47bcaa37d5a052eaf443a95287d851e1) --- source4/torture/vfs/fruit.c | 95 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 2167032..d4d5bd5 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3643,6 +3643,100 @@ 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; +} + /* * 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 @@ -3677,6 +3771,7 @@ struct torture_suite *torture_vfs_fruit(void) 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); return suite; } -- 2.9.3 From c130c77da38bbe496db0594243bbe0af002df82d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 15:44:37 +0100 Subject: [PATCH 52/60] lib/torture: add torture_assert_mem_equal_goto BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 49723151b2107553559c397adadda90f7c4806f7) --- lib/torture/torture.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/torture/torture.h b/lib/torture/torture.h index 45332b2..b6d1301 100644 --- a/lib/torture/torture.h +++ b/lib/torture/torture.h @@ -357,6 +357,16 @@ 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); \ + ret = false; \ + goto label; \ + } \ + } while(0) + static inline void torture_dump_data_str_cb(const char *buf, void *private_data) { char **dump = (char **)private_data; -- 2.9.3 From c5ea34605d6768c1e1c013dea4ea275dd40bccde Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 15:45:12 +0100 Subject: [PATCH 53/60] s4/torture: add test for AAPL find with name with illegal NTFS characters BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit c8baf2760ad51a7739084a8e2617c58c287b651e) --- source4/torture/vfs/fruit.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index d4d5bd5..38f5059 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3737,6 +3737,114 @@ done: 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; +} + /* * 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 @@ -3772,6 +3880,7 @@ struct torture_suite *torture_vfs_fruit(void) 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); return suite; } -- 2.9.3 From 0cc440c01021f0aa18e80c87448a86d5d94bf171 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 8 Dec 2016 17:47:36 +0100 Subject: [PATCH 54/60] docs/vfs_fruit: document known limitations with fruit:encoding=native BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit b302444f5b0675f0cb0f26fa2ad53e298067f7ab) --- docs-xml/manpages/vfs_fruit.8.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs-xml/manpages/vfs_fruit.8.xml b/docs-xml/manpages/vfs_fruit.8.xml index fe0cd3c..fe576a5 100644 --- a/docs-xml/manpages/vfs_fruit.8.xml +++ b/docs-xml/manpages/vfs_fruit.8.xml @@ -154,9 +154,13 @@ Controls how the set of illegal NTFS ASCII character, commonly used by OS X clients, are stored in - the filesystem: + the filesystem. - + Important: this is known to not fully + work with fruit:metadata=stream or + fruit:resource=stream. + + private (default) - store characters as encoded by the OS X client: mapped -- 2.9.3 From a11f221f8be5e2423e2ea652cccae4cdfa66cff6 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Dec 2016 19:02:37 +0100 Subject: [PATCH 55/60] s4/torture: change shares in used torture_suite_add_2ns_smb2_test() torture_suite_add_2ns_smb2_test wan't used, change it to use the default share as share 1 and a second share taken from torture option "torture:share2". BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 08dc5b4673a955f365095824275e67b2ea8fc31e) --- source4/torture/vfs/vfs.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c index 8b443fb..a4f8125 100644 --- a/source4/torture/vfs/vfs.c +++ b/source4/torture/vfs/vfs.c @@ -38,42 +38,44 @@ 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 ret = false; + bool ok; - struct smb2_tree *tree1; - struct smb2_tree *tree2; + struct smb2_tree *tree1 = NULL; + struct smb2_tree *tree2 = NULL; TALLOC_CTX *mem_ctx = talloc_new(torture_ctx); - if (!torture_smb2_con_sopt(torture_ctx, "share1", &tree1)) { + if (!torture_smb2_connection(torture_ctx, &tree1)) { torture_fail(torture_ctx, - "Establishing SMB2 connection failed\n"); - goto done; + "Establishing SMB2 connection failed\n"); + return false; } + /* + * This is a trick: + * The test might close the connection. If we steal the tree context + * before that and free the parent instead of tree directly, we avoid + * a double free error. + */ talloc_steal(mem_ctx, tree1); - if (!torture_smb2_con_sopt(torture_ctx, "share2", &tree2)) { - torture_fail(torture_ctx, - "Establishing SMB2 connection failed\n"); - goto done; + ok = torture_smb2_con_sopt(torture_ctx, "share2", &tree2); + if (ok) { + talloc_steal(mem_ctx, tree2); } - talloc_steal(mem_ctx, tree2); - fn = test->fn; - ret = fn(torture_ctx, tree1, tree2); + ok = fn(torture_ctx, tree1, tree2); -done: /* the test may already have closed some of the connections */ talloc_free(mem_ctx); - return ret; + return ok; } /* - * Run a test with 2 connected trees, Share names to connect are taken - * from option strings "torture:share1" and "torture:share2" + * Run a test with 2 connected trees, the default share and another + * taken from option strings "torture:share2" */ struct torture_test *torture_suite_add_2ns_smb2_test(struct torture_suite *suite, const char *name, -- 2.9.3 From cf001c7d7bc2e43317add91bff66b527806318e0 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Dec 2016 19:06:46 +0100 Subject: [PATCH 56/60] selftest: add shares without vfs_fruit for the vfs_fruit tests Not used for now, but the next commit will add a test that makes use of this. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit bac79eac093e042f22a77fa8e468f8c92bb3c113) --- selftest/target/Samba3.pm | 10 ++++++++++ source3/selftest/tests.py | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 9db578d..013e8d5 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1675,6 +1675,16 @@ sub provision($$$$$$$$) 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/source3/selftest/tests.py b/source3/selftest/tests.py index f537f10..c5d10f3 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -412,9 +412,9 @@ 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', 'metadata_netatalk') - plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_metadata_stream -U$USERNAME%$PASSWORD', 'metadata_stream') - plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_stream_depot -U$USERNAME%$PASSWORD', 'streams_depot') + 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') elif t == "rpc.schannel_anon_setpw": -- 2.9.3 From 65c73514786c9f1c6665b84243afc1a2cc7d2dc7 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Dec 2016 19:10:05 +0100 Subject: [PATCH 57/60] vfs_fruit: ignore or delete invalid AFP_AfpInfo streams BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit a2afd61906fbf36f75b2054abfd7384f220a14e3) --- source3/modules/vfs_fruit.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 981f950..fff981b 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -3527,7 +3527,26 @@ static ssize_t fruit_pread_meta_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); + 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, @@ -4365,6 +4384,50 @@ static NTSTATUS fruit_streaminfo_meta_stream( 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; } @@ -4376,8 +4439,11 @@ static NTSTATUS fruit_streaminfo_meta_netatalk( unsigned int *pnum_streams, struct stream_struct **pstreams) { + struct stream_struct *stream = *pstreams; + unsigned int num_streams = *pnum_streams; struct adouble *ad = NULL; bool is_fi_empty; + int i; bool ok; /* Remove the Netatalk xattr from the list */ @@ -4387,6 +4453,27 @@ static NTSTATUS fruit_streaminfo_meta_netatalk( return NT_STATUS_NO_MEMORY; } + /* + * 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; + } + } + + if (i < num_streams) { + DBG_WARNING("Unexpected AFPINFO_STREAM on [%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; + } + } + ad = ad_get(talloc_tos(), handle, smb_fname->base_name, ADOUBLE_META); if (ad == NULL) { -- 2.9.3 From 664883196bc43c550ba6a2b38c3312e81701c8ee Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 11 Dec 2016 19:11:09 +0100 Subject: [PATCH 58/60] s4/torture: vfs_fruit: test invalid AFPINFO_STREAM_NAME BUG: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit 8b7e88f368ce793699fc57272e74d0815219a250) --- source4/torture/vfs/fruit.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 38f5059..92ef06a 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -3845,6 +3845,64 @@ done: 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 @@ -3882,6 +3940,8 @@ struct torture_suite *torture_vfs_fruit(void) 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; } -- 2.9.3 From 75ff29859fcbc7cf6dfd41e8517866354c643d18 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 7 Feb 2017 15:01:53 +0100 Subject: [PATCH 59/60] vfs_fruit: use stat info from base_fsp This is also supposed to be valid in the VFS stack, so there's no need to re-stat here. Bug: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit ffa727f33b06e71403303b53797a068f455b22f8) --- source3/modules/vfs_fruit.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index fff981b..f1283c8 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2838,15 +2838,9 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - if (!(flags & O_CREAT) && !VALID_STAT(smb_fname->st)) { - rc = SMB_VFS_NEXT_STAT(handle, smb_fname); - if (rc != 0) { - rc = -1; - goto exit; - } - } - - if (VALID_STAT(smb_fname->st) && S_ISDIR(smb_fname->st.st_ex_mode)) { + if ((!(flags & O_CREAT)) && + S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode)) + { /* sorry, but directories don't habe a resource fork */ rc = -1; goto exit; -- 2.9.3 From ed40a9c56225b4c9015ecc27fc803e3e1dd6631a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 17 Feb 2017 16:35:44 +0100 Subject: [PATCH 60/60] s4/torture: vfs_fruit: add stream with illegal ntfs characters to copyile test This ensures a stream with illegal NTFS characters mapped to the Unicode private range like :foo\xef\x80\xa2bar:$DATA that is stored as an xattr name user.DosStream.foo:bar:$DATA if "fruit:encoding = native" is set, is copied by the special fruit copy_chunk request. Bug: https://bugzilla.samba.org/show_bug.cgi?id=12427 Signed-off-by: Ralph Boehme Reviewed-by: Uri Simchoni (cherry picked from commit c7a79a9b35225f41eeae961ab340882c7d49f0c4) --- source4/torture/vfs/fruit.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 92ef06a..d74a153 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -2451,6 +2451,7 @@ static bool test_copyfile(struct torture_context *torture, struct srv_copychunk_rsp cc_rsp; enum ndr_err_code ndr_ret; bool ok; + const char *sname = ":foo" "\xef\x80\xa2" "bar:$DATA"; /* * First test a copy_chunk with a 0 chunk count without having @@ -2521,6 +2522,11 @@ static bool test_copyfile(struct torture_context *torture, torture_fail(torture, "setup stream error"); } + ok = write_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_SRC, sname, + 10, 10, "abcdefghij"); + torture_assert_goto(torture, ok == true, ok, done, "write_stream failed\n"); + ok = test_setup_copy_chunk(torture, tree, tmp_ctx, 0, /* 0 chunks, copyfile semantics */ &src_h, 4096, /* fill 4096 byte src file */ @@ -2573,6 +2579,11 @@ static bool test_copyfile(struct torture_context *torture, torture_fail_goto(torture, done, "inconsistent stream data"); } + ok = check_stream(tree, __location__, torture, tmp_ctx, + FNAME_CC_DST, sname, + 0, 20, 10, 10, "abcdefghij"); + torture_assert_goto(torture, ok == true, ok, done, "check_stream failed\n"); + done: smb2_util_close(tree, src_h); smb2_util_close(tree, dest_h); -- 2.9.3