From ef2c81eb9fe5e12d5694af665be198994e02762d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 2 Dec 2016 15:49:03 +0100 Subject: [PATCH] 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 --- 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 50d06528022..6f5ca7ea8fd 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;