From 35765b8fa433d930a3d533e8f6728b2910026384 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 20 May 2020 22:18:54 +0200 Subject: [PATCH] vfs_streams_xattr: implement SMB_VFS_OPENAT() Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- source3/modules/vfs_streams_xattr.c | 153 ++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index ff64d10f4d4..8e8f56a3840 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -498,6 +498,158 @@ static int streams_xattr_open(vfs_handle_struct *handle, return -1; } +static int streams_xattr_openat(struct vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + files_struct *fsp, + int flags, + mode_t mode) +{ + NTSTATUS status; + struct streams_xattr_config *config = NULL; + struct stream_io *sio = NULL; + struct ea_struct ea; + char *xattr_name = NULL; + int pipe_fds[2]; + int fakefd = -1; + bool set_empty_xattr = false; + int ret; + + /* + * For now assert this, so the below SMB_VFS_SETXATTR() works. + */ + SMB_ASSERT(dirfsp->fh->fd == AT_FDCWD); + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config, + return -1); + + DEBUG(10, ("streams_xattr_open called for %s with flags 0x%x\n", + smb_fname_str_dbg(smb_fname), flags)); + + if (!is_named_stream(smb_fname)) { + return SMB_VFS_NEXT_OPENAT(handle, + dirfsp, + smb_fname, + fsp, + flags, + mode); + } + + status = streams_xattr_get_name(handle, talloc_tos(), + smb_fname->stream_name, &xattr_name); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto fail; + } + + status = get_ea_value(talloc_tos(), handle->conn, NULL, + smb_fname, xattr_name, &ea); + + DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status))); + + if (!NT_STATUS_IS_OK(status)) { + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + /* + * The base file is not there. This is an error even if + * we got O_CREAT, the higher levels should have created + * the base file for us. + */ + DBG_DEBUG("streams_xattr_open: base file %s not around, " + "returning ENOENT\n", smb_fname->base_name); + errno = ENOENT; + goto fail; + } + + if (!(flags & O_CREAT)) { + errno = ENOATTR; + goto fail; + } + + set_empty_xattr = true; + } + + if (flags & O_TRUNC) { + set_empty_xattr = true; + } + + if (set_empty_xattr) { + /* + * The attribute does not exist or needs to be truncated + */ + + /* + * Darn, xattrs need at least 1 byte + */ + char null = '\0'; + + DEBUG(10, ("creating or truncating attribute %s on file %s\n", + xattr_name, smb_fname->base_name)); + + ret = SMB_VFS_SETXATTR(fsp->conn, + smb_fname, + xattr_name, + &null, sizeof(null), + flags & O_EXCL ? XATTR_CREATE : 0); + if (ret != 0) { + goto fail; + } + } + + /* + * Return a valid fd, but ensure any attempt to use it returns an error + * (EPIPE). + */ + ret = pipe(pipe_fds); + if (ret != 0) { + goto fail; + } + + close(pipe_fds[1]); + pipe_fds[1] = -1; + fakefd = pipe_fds[0]; + + sio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct stream_io, NULL); + if (sio == NULL) { + errno = ENOMEM; + goto fail; + } + + sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), + xattr_name); + if (sio->xattr_name == NULL) { + errno = ENOMEM; + goto fail; + } + + /* + * so->base needs to be a copy of fsp->fsp_name->base_name, + * making it identical to streams_xattr_recheck(). If the + * open is changing directories, fsp->fsp_name->base_name + * will be the full path from the share root, whilst + * smb_fname will be relative to the $cwd. + */ + sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp), + fsp->fsp_name->base_name); + if (sio->base == NULL) { + errno = ENOMEM; + goto fail; + } + + sio->fsp_name_ptr = fsp->fsp_name; + sio->handle = handle; + sio->fsp = fsp; + + return fakefd; + + fail: + if (fakefd >= 0) { + close(fakefd); + fakefd = -1; + } + + return -1; +} + static int streams_xattr_close(vfs_handle_struct *handle, files_struct *fsp) { @@ -1639,6 +1791,7 @@ static struct vfs_fn_pointers vfs_streams_xattr_fns = { .fs_capabilities_fn = streams_xattr_fs_capabilities, .connect_fn = streams_xattr_connect, .open_fn = streams_xattr_open, + .openat_fn = streams_xattr_openat, .close_fn = streams_xattr_close, .stat_fn = streams_xattr_stat, .fstat_fn = streams_xattr_fstat,