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

index 0636ce94fd0281c4883de10ab798c7bc55c7c035..7df41aa4301abe05e375fd861fa3a0989728f318 100644 (file)
@@ -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));
@@ -1232,22 +1285,145 @@ exit:
        return ad;
 }
 
+/**
+ * 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));