1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-26 10:04:02 +03:00

vfs_streams_xattr: implement SMB_VFS_OPENAT()

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Ralph Boehme 2020-05-20 22:18:54 +02:00 committed by Jeremy Allison
parent dcddc45c4c
commit 35765b8fa4

View File

@ -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,