vfs_fruit: refactor fruit_streaminfo()
authorRalph Boehme <slow@samba.org>
Fri, 2 Dec 2016 14:49:03 +0000 (15:49 +0100)
committerUri Simchoni <uri@samba.org>
Wed, 1 Mar 2017 23:32:21 +0000 (00:32 +0100)
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 <slow@samba.org>
Reviewed-by: Uri Simchoni <uri@samba.org>
source3/modules/vfs_fruit.c

index 50d06528022143c415f88763ead1507ac3a5b48d..6f5ca7ea8fd0af0e9039629a9059eb8b69123285 100644 (file)
@@ -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;