summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalph Boehme <slow@samba.org>2016-12-08 20:38:17 +0100
committerStefan Metzmacher <metze@samba.org>2017-03-07 08:28:14 +0100
commit93815feca1f4f51fe5492d0368e7fb67c824b129 (patch)
tree0978948473164031fc334dc175fcbc8c5be73613
parente7701ed1485f6a8ee3c851a8bb8d08b016e4f671 (diff)
downloadsamba-93815feca1f4f51fe5492d0368e7fb67c824b129.tar.gz
vfs_fruit: refactor fruit_pread and fruit_pwrite and use new adouble API
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> (cherry picked from commit fcb9c840d7d082457c3136a44a23b489c98b0327)
-rw-r--r--source3/modules/vfs_fruit.c524
1 files changed, 349 insertions, 175 deletions
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index 13a8af07ae1..81f3ac974fe 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -3508,233 +3508,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.
*/