const char *stream_name,
char **xattr_name)
{
- char *sname;
+ size_t stream_name_len = strlen(stream_name);
char *stype;
struct streams_xattr_config *config;
SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
return NT_STATUS_UNSUCCESSFUL);
- sname = talloc_strdup(ctx, stream_name + 1);
- if (sname == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ SMB_ASSERT(stream_name[0] == ':');
+ stream_name += 1;
/*
* With vfs_fruit option "fruit:encoding = native" we're
* In check_path_syntax() we've already ensured the streamname
* we got from the client is valid.
*/
- stype = strrchr_m(sname, ':');
+ stype = strrchr_m(stream_name, ':');
if (stype) {
/*
* We only support one stream type: "$DATA"
*/
if (strcasecmp_m(stype, ":$DATA") != 0) {
- talloc_free(sname);
return NT_STATUS_INVALID_PARAMETER;
}
/* Split name and type */
- stype[0] = '\0';
+ stream_name_len = (stype - stream_name);
}
- *xattr_name = talloc_asprintf(ctx, "%s%s%s",
+ *xattr_name = talloc_asprintf(ctx, "%s%.*s%s",
config->prefix,
- sname,
+ (int)stream_name_len,
+ stream_name,
config->store_stream_type ? ":$DATA" : "");
if (*xattr_name == NULL) {
- talloc_free(sname);
return NT_STATUS_NO_MEMORY;
}
DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
stream_name));
- talloc_free(sname);
return NT_STATUS_OK;
}
struct stream_io *io = (struct stream_io *)
VFS_FETCH_FSP_EXTENSION(handle, fsp);
- if (io == NULL || fsp->base_fsp == NULL) {
+ if (io == NULL || !fsp_is_alternate_stream(fsp)) {
return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
}
const struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
files_struct *fsp,
- int flags,
- mode_t mode)
+ const struct vfs_open_how *how)
{
NTSTATUS status;
struct streams_xattr_config *config = NULL;
DBG_DEBUG("called for %s with flags 0x%x\n",
smb_fname_str_dbg(smb_fname),
- flags);
+ how->flags);
if (!is_named_stream(smb_fname)) {
return SMB_VFS_NEXT_OPENAT(handle,
dirfsp,
smb_fname,
fsp,
- flags,
- mode);
+ how);
}
- /*
- * For now assert this, so the below SMB_VFS_SETXATTR() works.
- */
- SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
+ if (how->resolve != 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ SMB_ASSERT(fsp_is_alternate_stream(fsp));
+ SMB_ASSERT(dirfsp == NULL);
status = streams_xattr_get_name(handle, talloc_tos(),
smb_fname->stream_name, &xattr_name);
goto fail;
}
- if (!(flags & O_CREAT)) {
+ if (!(how->flags & O_CREAT)) {
errno = ENOATTR;
goto fail;
}
set_empty_xattr = true;
}
- if (flags & O_TRUNC) {
+ if (how->flags & O_TRUNC) {
set_empty_xattr = true;
}
ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
xattr_name,
&null, sizeof(null),
- flags & O_EXCL ? XATTR_CREATE : 0);
+ how->flags & O_EXCL ? XATTR_CREATE : 0);
if (ret != 0) {
goto fail;
}
DBG_DEBUG("streams_xattr_close called [%s] fd [%d]\n",
smb_fname_str_dbg(fsp->fsp_name), fd);
- if (!is_named_stream(fsp->fsp_name)) {
+ if (!fsp_is_alternate_stream(fsp)) {
return SMB_VFS_NEXT_CLOSE(handle, fsp);
}
return ret;
}
-static int streams_xattr_unlink_internal(vfs_handle_struct *handle,
+static int streams_xattr_unlinkat(vfs_handle_struct *handle,
struct files_struct *dirfsp,
const struct smb_filename *smb_fname,
int flags)
NTSTATUS status;
int ret = -1;
char *xattr_name = NULL;
+ struct smb_filename *pathref = NULL;
+ struct files_struct *fsp = smb_fname->fsp;
if (!is_named_stream(smb_fname)) {
return SMB_VFS_NEXT_UNLINKAT(handle,
flags);
}
+ /* A stream can never be rmdir'ed */
+ SMB_ASSERT((flags & AT_REMOVEDIR) == 0);
+
status = streams_xattr_get_name(handle, talloc_tos(),
smb_fname->stream_name, &xattr_name);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- SMB_ASSERT(smb_fname->fsp != NULL);
- SMB_ASSERT(smb_fname->fsp->base_fsp != NULL);
+ if (fsp == NULL) {
+ status = synthetic_pathref(talloc_tos(),
+ handle->conn->cwd_fsp,
+ smb_fname->base_name,
+ NULL,
+ NULL,
+ smb_fname->twrp,
+ smb_fname->flags,
+ &pathref);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = ENOENT;
+ goto fail;
+ }
+ fsp = pathref->fsp;
+ } else {
+ SMB_ASSERT(fsp_is_alternate_stream(smb_fname->fsp));
+ fsp = fsp->base_fsp;
+ }
- ret = SMB_VFS_FREMOVEXATTR(smb_fname->fsp->base_fsp, xattr_name);
+ ret = SMB_VFS_FREMOVEXATTR(fsp, xattr_name);
if ((ret == -1) && (errno == ENOATTR)) {
errno = ENOENT;
fail:
TALLOC_FREE(xattr_name);
- return ret;
-}
-
-static int streams_xattr_unlinkat(vfs_handle_struct *handle,
- struct files_struct *dirfsp,
- const struct smb_filename *smb_fname,
- int flags)
-{
- int ret;
- if (flags & AT_REMOVEDIR) {
- ret = SMB_VFS_NEXT_UNLINKAT(handle,
- dirfsp,
- smb_fname,
- flags);
- } else {
- ret = streams_xattr_unlink_internal(handle,
- dirfsp,
- smb_fname,
- flags);
- }
+ TALLOC_FREE(pathref);
return ret;
}
return true;
}
+static int streams_xattr_fcntl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ int cmd,
+ va_list cmd_arg)
+{
+ va_list dup_cmd_arg;
+ void *arg;
+ int ret;
+
+ if (fsp_is_alternate_stream(fsp)) {
+ switch (cmd) {
+ case F_GETFL:
+ case F_SETFL:
+ break;
+ default:
+ DBG_ERR("Unsupported fcntl() cmd [%d] on [%s]\n",
+ cmd, fsp_str_dbg(fsp));
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ va_copy(dup_cmd_arg, cmd_arg);
+ arg = va_arg(dup_cmd_arg, void *);
+
+ ret = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg);
+
+ va_end(dup_cmd_arg);
+
+ return ret;
+}
+
static struct vfs_fn_pointers vfs_streams_xattr_fns = {
.fs_capabilities_fn = streams_xattr_fs_capabilities,
.connect_fn = streams_xattr_connect,
.filesystem_sharemode_fn = streams_xattr_filesystem_sharemode,
.linux_setlease_fn = streams_xattr_linux_setlease,
.strict_lock_check_fn = streams_xattr_strict_lock_check,
+ .fcntl_fn = streams_xattr_fcntl,
.fchown_fn = streams_xattr_fchown,
.fchmod_fn = streams_xattr_fchmod,