]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_fruit: refactor fruit_pread and fruit_pwrite and use new adouble API
authorRalph Boehme <slow@samba.org>
Thu, 8 Dec 2016 19:38:17 +0000 (20:38 +0100)
committerUri Simchoni <uri@samba.org>
Wed, 1 Mar 2017 23:32:22 +0000 (00:32 +0100)
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 <slow@samba.org>
Reviewed-by: Uri Simchoni <uri@samba.org>
source3/modules/vfs_fruit.c

index 29dca862440db42907e396d217c0a8d03cff479e..aaa7391c8a16c6bfe058848f7462881bd63d1fd2 100644 (file)
@@ -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.
  */