The branch, master has been updated via 480516e3b85 vfs_fruit: make use of adouble_open_from_base_fsp(ADOUBLE_RSRC) in fruit_open_rsrc_adouble() via 0b8c6e736af vfs_fruit: add fruit_get_complete_fio() helper via 94799dc8e61 vfs_fruit: let fruit_open_rsrc_adouble() return errno = EISDIR via d62c670c3dd s3:adouble: add adouble_open_from_base_fsp() via c45a8d753d3 s3:adouble: allow ad_fget/ad_get_internal to be used with a backend fsp via db743ab005b share_mode_lock: DEBUG/ASSERT recursion deadlock detection via 1052314dcd0 s3:adouble: rewrite ad_open_rsrc() as adouble_open_rsrc_fsp() using create_internal_fsp() from ff16c74ee2b WHATSNEW: Start release notes for Samba 4.15.0pre1.
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 480516e3b850035d188b8dab8490c63e0a7afe80 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Dec 8 16:29:10 2020 +0100 vfs_fruit: make use of adouble_open_from_base_fsp(ADOUBLE_RSRC) in fruit_open_rsrc_adouble() The key is that we return a fake_fd to the caller and only open the '._' file in the background. The next vfs backend should only see the fsp from adouble_open_from_base_fsp, while the vfs backends above should only see the fake_fd. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Autobuild-User(master): Ralph Böhme <s...@samba.org> Autobuild-Date(master): Thu Jan 21 14:47:53 UTC 2021 on sn-devel-184 commit 0b8c6e736afbec7ea1f69219c54a33031db3b8d9 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Dec 10 13:11:06 2020 +0100 vfs_fruit: add fruit_get_complete_fio() helper This will make it easier to hide some fsp extension later. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 94799dc8e61126f0bdd566e0d054424aebd9d477 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 30 13:49:37 2020 +0100 vfs_fruit: let fruit_open_rsrc_adouble() return errno = EISDIR That hopefully makes the check that ':AFP_Resource' can't be created on directories. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit d62c670c3dd33eafc515ee92be177d1ddcb7b0a9 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 23 11:58:08 2020 +0100 s3:adouble: add adouble_open_from_base_fsp() For now we only support ADOUBLE_RSRC, but that might change in future. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit c45a8d753d3a415d2a8038d1327276ecb972b036 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 23 11:58:08 2020 +0100 s3:adouble: allow ad_fget/ad_get_internal to be used with a backend fsp Up to now we only passed in stream fsp, but that will change shortly. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit db743ab005bc7671d4fb0f5bea895c1097b707c5 Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 23 11:59:05 2020 +0100 share_mode_lock: DEBUG/ASSERT recursion deadlock detection This situation should never happen! The known trigger is fixed with the change to adouble_open_rsrc_fsp() Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> commit 1052314dcd05738f29d1ae85a5a4b8eaa4babe3d Author: Stefan Metzmacher <me...@samba.org> Date: Wed Dec 23 11:58:08 2020 +0100 s3:adouble: rewrite ad_open_rsrc() as adouble_open_rsrc_fsp() using create_internal_fsp() "._" AppleDouble files are hidden by vfs_fruit by default, so there's no need to go through a full SMB_VFS_CREATE_FILE() for them. They don't need an smbXsrv_open_global.tdb entry nor a locking.tdb entry, so we just open them with fd_openat(). This avoids a recursion deadlock in get_share_mode_lock() when closing the ':AFP_Resource' stream. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/lib/adouble.c | 146 ++++++++++++-------- source3/lib/adouble.h | 6 + source3/locking/share_mode_lock.c | 21 ++- source3/modules/vfs_fruit.c | 284 ++++++++++++++++++++++++++------------ 4 files changed, 314 insertions(+), 143 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/lib/adouble.c b/source3/lib/adouble.c index dffc0d5b7be..e869965876d 100644 --- a/source3/lib/adouble.c +++ b/source3/lib/adouble.c @@ -2091,71 +2091,95 @@ exit: return ealen; } -static int ad_open_rsrc(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - int flags, - mode_t mode, - files_struct **_fsp) +static NTSTATUS adouble_open_rsrc_fsp(const struct files_struct *dirfsp, + const struct smb_filename *smb_base_fname, + int in_flags, + mode_t mode, + struct files_struct **_ad_fsp) { - int ret; + int rc = 0; + struct adouble *ad = NULL; struct smb_filename *adp_smb_fname = NULL; - files_struct *fsp = NULL; - uint32_t access_mask; - uint32_t share_access; - uint32_t create_disposition; + struct files_struct *ad_fsp = NULL; NTSTATUS status; + int flags = in_flags; - ret = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname); - if (ret != 0) { - return -1; + rc = adouble_path(talloc_tos(), + smb_base_fname, + &adp_smb_fname); + if (rc != 0) { + return NT_STATUS_NO_MEMORY; } - ret = SMB_VFS_STAT(handle->conn, adp_smb_fname); - if (ret != 0) { - TALLOC_FREE(adp_smb_fname); - return -1; + status = create_internal_fsp(dirfsp->conn, + adp_smb_fname, + &ad_fsp); + if (!NT_STATUS_IS_OK(status)) { + return status; } - access_mask = FILE_GENERIC_READ; - share_access = FILE_SHARE_READ | FILE_SHARE_WRITE; - create_disposition = FILE_OPEN; - - if (flags & O_RDWR) { - access_mask |= FILE_GENERIC_WRITE; - share_access &= ~FILE_SHARE_WRITE; +#ifdef O_PATH + flags &= ~(O_PATH); +#endif + if (flags & (O_CREAT | O_TRUNC | O_WRONLY)) { + /* We always need read/write access for the metadata header too */ + flags &= ~(O_WRONLY); + flags |= O_RDWR; } - status = openat_pathref_fsp(handle->conn->cwd_fsp, adp_smb_fname); + status = fd_openat(dirfsp, + adp_smb_fname, + ad_fsp, + flags, + mode); if (!NT_STATUS_IS_OK(status)) { - return -1; + file_free(NULL, ad_fsp); + return status; } - status = SMB_VFS_CREATE_FILE( - handle->conn, /* conn */ - NULL, /* req */ - adp_smb_fname, - access_mask, - share_access, - 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, - NULL, /* psbuf */ - NULL, NULL); /* create context */ - TALLOC_FREE(adp_smb_fname); - if (!NT_STATUS_IS_OK(status)) { - DBG_ERR("SMB_VFS_CREATE_FILE failed\n"); - return -1; + if (flags & (O_CREAT | O_TRUNC)) { + ad = ad_init(talloc_tos(), ADOUBLE_RSRC); + if (ad == NULL) { + file_free(NULL, ad_fsp); + return NT_STATUS_NO_MEMORY; + } + + rc = ad_fset(ad_fsp->conn->vfs_handles, ad, ad_fsp); + if (rc != 0) { + file_free(NULL, ad_fsp); + return NT_STATUS_IO_DEVICE_ERROR; + } + TALLOC_FREE(ad); } - *_fsp = fsp; - return 0; + *_ad_fsp = ad_fsp; + return NT_STATUS_OK; +} + +NTSTATUS adouble_open_from_base_fsp(const struct files_struct *dirfsp, + struct files_struct *base_fsp, + adouble_type_t type, + int flags, + mode_t mode, + struct files_struct **_ad_fsp) +{ + *_ad_fsp = NULL; + + SMB_ASSERT(base_fsp != NULL); + SMB_ASSERT(base_fsp->base_fsp == NULL); + + switch (type) { + case ADOUBLE_META: + return NT_STATUS_INTERNAL_ERROR; + case ADOUBLE_RSRC: + return adouble_open_rsrc_fsp(dirfsp, + base_fsp->fsp_name, + flags, + mode, + _ad_fsp); + } + + return NT_STATUS_INTERNAL_ERROR; } /* @@ -2170,7 +2194,7 @@ static int ad_open(vfs_handle_struct *handle, int flags, mode_t mode) { - int ret; + NTSTATUS status; DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name, ad->ad_type == ADOUBLE_META ? "meta" : "rsrc"); @@ -2185,8 +2209,13 @@ static int ad_open(vfs_handle_struct *handle, return 0; } - ret = ad_open_rsrc(handle, smb_fname, flags, mode, &ad->ad_fsp); - if (ret != 0) { + status = adouble_open_rsrc_fsp(handle->conn->cwd_fsp, + smb_fname, + flags, + mode, + &ad->ad_fsp); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); return -1; } ad->ad_opened = true; @@ -2291,11 +2320,14 @@ static int adouble_destructor(struct adouble *ad) SMB_ASSERT(ad->ad_fsp != NULL); - status = close_file(NULL, ad->ad_fsp, NORMAL_CLOSE); + status = fd_close(ad->ad_fsp); if (!NT_STATUS_IS_OK(status)) { DBG_ERR("Closing [%s] failed: %s\n", fsp_str_dbg(ad->ad_fsp), nt_errstr(status)); } + file_free(NULL, ad->ad_fsp); + ad->ad_fsp = NULL; + ad->ad_opened = false; return 0; } @@ -2434,7 +2466,11 @@ static struct adouble *ad_get_internal(TALLOC_CTX *ctx, int mode; if (fsp != NULL) { - smb_fname = fsp->base_fsp->fsp_name; + if (fsp->base_fsp != NULL) { + smb_fname = fsp->base_fsp->fsp_name; + } else { + smb_fname = fsp->fsp_name; + } } DEBUG(10, ("ad_get(%s) called for %s\n", diff --git a/source3/lib/adouble.h b/source3/lib/adouble.h index 90a825c502e..a5761281670 100644 --- a/source3/lib/adouble.h +++ b/source3/lib/adouble.h @@ -164,6 +164,12 @@ bool ad_unconvert(TALLOC_CTX *mem_ctx, struct smb_filename *smb_fname, bool *converted); struct adouble *ad_init(TALLOC_CTX *ctx, adouble_type_t type); +NTSTATUS adouble_open_from_base_fsp(const struct files_struct *dirfsp, + struct files_struct *base_fsp, + adouble_type_t type, + int flags, + mode_t mode, + struct files_struct **_ad_fsp); struct adouble *ad_get(TALLOC_CTX *ctx, vfs_handle_struct *handle, const struct smb_filename *smb_fname, diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index 80c04fdeda0..e8bb3e58e1f 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -880,8 +880,15 @@ struct share_mode_lock *get_share_mode_lock( if (static_share_mode_data != NULL) { if (!file_id_equal(&static_share_mode_data->id, &id)) { - DEBUG(1, ("Can not lock two share modes " - "simultaneously\n")); + struct file_id_buf existing; + struct file_id_buf requested; + + DBG_ERR("Can not lock two share modes " + "simultaneously: existing %s requested %s\n", + file_id_str_buf(static_share_mode_data->id, &existing), + file_id_str_buf(id, &requested)); + + smb_panic(__location__); goto fail; } goto done; @@ -904,6 +911,7 @@ struct share_mode_lock *get_share_mode_lock( cmp = tdb_data_cmp(share_mode_lock_key, key); if (cmp != 0) { DBG_WARNING("Can not lock two share modes simultaneously\n"); + smb_panic(__location__); goto fail; } @@ -929,6 +937,15 @@ done: talloc_set_destructor(lck, share_mode_lock_destructor); + if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) { + struct file_id_buf returned; + + DBG_DEBUG("Returning %s (data_refcount=%zu key_refcount=%zu)\n", + file_id_str_buf(id, &returned), + static_share_mode_data_refcount, + share_mode_lock_key_refcount); + } + return lck; fail: TALLOC_FREE(lck); diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index b25aebfa9ac..f5b5f91a012 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -172,9 +172,17 @@ static const struct enum_list fruit_encoding[] = { }; struct fio { + vfs_handle_struct *handle; + files_struct *fsp; /* backlink to itself */ + /* tcon config handle */ struct fruit_config_data *config; + /* Backend fsp for AppleDouble file, can be NULL */ + files_struct *ad_fsp; + /* link from adouble_open_from_base_fsp() to fio */ + struct fio *real_fio; + /* Denote stream type, meta or rsrc */ adouble_type_t type; @@ -194,6 +202,27 @@ struct fio { * Helper functions *****************************************************************************/ +static struct fio *fruit_get_complete_fio(vfs_handle_struct *handle, + files_struct *fsp) +{ + struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp); + + if (fio == NULL) { + return NULL; + } + + if (fio->real_fio != NULL) { + /* + * This is an fsp from adouble_open_from_base_fsp() + * we should just pass this to the next + * module. + */ + return NULL; + } + + return fio; +} + /** * Initialize config struct from our smb.conf config parameters **/ @@ -1313,6 +1342,32 @@ static int fruit_connect(vfs_handle_struct *handle, return rc; } +static void fio_ref_destroy_fn(void *p_data) +{ + struct fio *ref_fio = (struct fio *)p_data; + if (ref_fio->real_fio != NULL) { + SMB_ASSERT(ref_fio->real_fio->ad_fsp == ref_fio->fsp); + ref_fio->real_fio->ad_fsp = NULL; + ref_fio->real_fio = NULL; + } +} + +static void fio_close_ad_fsp(struct fio *fio) +{ + if (fio->ad_fsp != NULL) { + fd_close(fio->ad_fsp); + file_free(NULL, fio->ad_fsp); + /* fio_ref_destroy_fn() should have cleared this */ + SMB_ASSERT(fio->ad_fsp == NULL); + } +} + +static void fio_destroy_fn(void *p_data) +{ + struct fio *fio = (struct fio *)p_data; + fio_close_ad_fsp(fio); +} + static int fruit_open_meta_stream(vfs_handle_struct *handle, const struct files_struct *dirfsp, const struct smb_filename *smb_fname, @@ -1330,7 +1385,9 @@ static int fruit_open_meta_stream(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL); + fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn); + fio->handle = handle; + fio->fsp = fsp; fio->type = ADOUBLE_META; fio->config = config; @@ -1397,7 +1454,9 @@ static int fruit_open_meta_netatalk(vfs_handle_struct *handle, SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); - fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL); + fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn); + fio->handle = handle; + fio->fsp = fsp; fio->type = ADOUBLE_META; fio->config = config; fio->fake_fd = true; @@ -1449,10 +1508,12 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, mode_t mode) { int rc = 0; - struct adouble *ad = NULL; - struct smb_filename *smb_fname_base = NULL; struct fruit_config_data *config = NULL; - int hostfd = -1; + struct files_struct *ad_fsp = NULL; + struct fio *fio = NULL; + struct fio *ref_fio = NULL; + NTSTATUS status; + int fd = -1; SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data, return -1); @@ -1461,68 +1522,82 @@ static int fruit_open_rsrc_adouble(vfs_handle_struct *handle, S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode)) { /* sorry, but directories don't habe a resource fork */ + errno = EISDIR; rc = -1; goto exit; } - rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_base); - if (rc != 0) { + /* + * We return a fake_fd to the vfs modules above, + * while we open an internal backend fsp for the + * '._' file for the next vfs modules. + * + * Note that adouble_open_from_base_fsp() recurses + * into fruit_openat(), but it'll just pass to + * the next module as just opens a flat file on + * disk. + */ + + fd = vfs_fake_fd(); + if (fd == -1) { + rc = fd; goto exit; } - /* We always need read/write access for the metadata header too */ - flags &= ~(O_RDONLY | O_WRONLY); - flags |= O_RDWR; - - hostfd = SMB_VFS_NEXT_OPENAT(handle, - dirfsp, - smb_fname_base, - fsp, - flags, - mode); - if (hostfd == -1) { + status = adouble_open_from_base_fsp(dirfsp, + fsp->base_fsp, + ADOUBLE_RSRC, + flags, + mode, + &ad_fsp); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); rc = -1; goto exit; } - if (flags & (O_CREAT | O_TRUNC)) { - ad = ad_init(fsp, ADOUBLE_RSRC); - if (ad == NULL) { - rc = -1; - goto exit; - } - - fsp_set_fd(fsp, hostfd); + /* + * Now we need to glue both handles together, + * so that they automatically detach each other + * on close. + */ + fio = fruit_get_complete_fio(handle, fsp); - rc = ad_fset(handle, ad, fsp); - fsp_set_fd(fsp, -1); - if (rc != 0) { - rc = -1; - goto exit; - } - TALLOC_FREE(ad); + ref_fio = VFS_ADD_FSP_EXTENSION(handle, ad_fsp, + struct fio, + fio_ref_destroy_fn); + if (ref_fio == NULL) { + int saved_errno = errno; + fd_close(ad_fsp); + file_free(NULL, ad_fsp); + ad_fsp = NULL; + errno = saved_errno; + rc = -1; + goto exit; } -exit: + SMB_ASSERT(ref_fio->fsp == NULL); + ref_fio->handle = handle; + ref_fio->fsp = ad_fsp; + ref_fio->type = ADOUBLE_RSRC; + ref_fio->config = config; + ref_fio->real_fio = fio; + SMB_ASSERT(fio->ad_fsp == NULL); + fio->ad_fsp = ad_fsp; + fio->fake_fd = true; - TALLOC_FREE(smb_fname_base); +exit: - DEBUG(10, ("fruit_open resource fork: rc=%d, fd=%d\n", rc, hostfd)); + DEBUG(10, ("fruit_open resource fork: rc=%d\n", rc)); if (rc != 0) { int saved_errno = errno; - if (hostfd >= 0) { - /* - * BUGBUGBUG -- we would need to call - * fd_close_posix here, but we don't have a - * full fsp yet - */ - fsp_set_fd(fsp, hostfd); - SMB_VFS_CLOSE(fsp); -- Samba Shared Repository