diff options
author | Ralph Boehme <slow@samba.org> | 2016-12-08 20:38:17 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2017-03-06 19:40:21 +0100 |
commit | 408d21faca6e9cf78817300caec0ca01124884cf (patch) | |
tree | 378cdf2de5c43ebdf5d914dbc30ada2b8bbef1d1 /source3/modules | |
parent | 96b51a43784760202f55083d3793a2d98352fbbb (diff) | |
download | samba-408d21faca6e9cf78817300caec0ca01124884cf.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)
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/vfs_fruit.c | 524 |
1 files changed, 349 insertions, 175 deletions
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 3443c81d7a0..86f08599153 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -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. */ |