vfs_streams_xattr: implement SMB_VFS_OPENAT()
authorRalph Boehme <slow@samba.org>
Wed, 20 May 2020 20:18:54 +0000 (22:18 +0200)
committerJeremy Allison <jra@samba.org>
Thu, 21 May 2020 20:38:33 +0000 (20:38 +0000)
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_streams_xattr.c

index ff64d10f4d437a58f924899aeb4bb4d227c5a217..8e8f56a38403adeda95347bb9ed559b515473d5d 100644 (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,