Esempio n. 1
0
static int streams_xattr_stat(vfs_handle_struct *handle,
			      struct smb_filename *smb_fname)
{
	NTSTATUS status;
	int result = -1;
	char *xattr_name = NULL;

	if (!is_ntfs_stream_smb_fname(smb_fname)) {
		return SMB_VFS_NEXT_STAT(handle, smb_fname);
	}

	/* Note if lp_posix_paths() is true, we can never
	 * get here as is_ntfs_stream_smb_fname() is
	 * always false. So we never need worry about
	 * not following links here. */

	/* If the default stream is requested, just stat the base file. */
	if (is_ntfs_default_stream_smb_fname(smb_fname)) {
		return streams_xattr_stat_base(handle, smb_fname, true);
	}

	/* Populate the stat struct with info from the base file. */
	if (streams_xattr_stat_base(handle, smb_fname, true) == -1) {
		return -1;
	}

	/* Derive the xattr name to lookup. */
	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);
		return -1;
	}

	/* Augment the base file's stat information before returning. */
	smb_fname->st.st_ex_size = get_xattr_size(handle->conn,
						  smb_fname,
						  xattr_name);
	if (smb_fname->st.st_ex_size == -1) {
		SET_STAT_INVALID(smb_fname->st);
		errno = ENOENT;
		result = -1;
		goto fail;
	}

	smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
	smb_fname->st.st_ex_mode &= ~S_IFMT;
	smb_fname->st.st_ex_mode &= ~S_IFDIR;
        smb_fname->st.st_ex_mode |= S_IFREG;
        smb_fname->st.st_ex_blocks =
	    smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;

	result = 0;
 fail:
	TALLOC_FREE(xattr_name);
	return result;
}
Esempio n. 2
0
NTSTATUS onefs_stream_prep_smb_fname(TALLOC_CTX *ctx,
				     const struct smb_filename *smb_fname_in,
				     struct smb_filename **smb_fname_out)
{
	char *stream_name = NULL;
	NTSTATUS status;

	/*
	 * Only attempt to strip off the trailing :$DATA if there is an actual
	 * stream there.  If it is the default stream, the smb_fname_out will
	 * just have a NULL stream so the base file is opened.
	 */
	if (smb_fname_in->stream_name &&
	    !is_ntfs_default_stream_smb_fname(smb_fname_in)) {
		char *str_tmp = smb_fname_in->stream_name;

		/* First strip off the leading ':' */
		if (str_tmp[0] == ':') {
			str_tmp++;
		}

		/* Create a new copy of the stream_name. */
		stream_name = talloc_strdup(ctx, str_tmp);
		if (stream_name == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		/* Strip off the :$DATA if one exists. */
		str_tmp = strrchr_m(stream_name, ':');
		if (str_tmp) {
			if (strcasecmp_m(str_tmp, ":$DATA") != 0) {
				return NT_STATUS_INVALID_PARAMETER;
			}
			str_tmp[0] = '\0';
		}
	}

	/*
	 * If there was a stream that wasn't the default stream the leading
	 * colon and trailing :$DATA has now been stripped off.  Create a new
	 * smb_filename to pass back.
	 */
	status = create_synthetic_smb_fname(ctx, smb_fname_in->base_name,
					    stream_name, &smb_fname_in->st,
					    smb_fname_out);
	TALLOC_FREE(stream_name);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5, ("Failed to prep stream name for %s: %s\n",
			  *smb_fname_out ?
			  smb_fname_str_dbg(*smb_fname_out) : "NULL",
			  nt_errstr(status)));
	}
	return status;
}
Esempio n. 3
0
static int streams_xattr_unlink(vfs_handle_struct *handle,
				const struct smb_filename *smb_fname)
{
	NTSTATUS status;
	int ret = -1;
	char *xattr_name = NULL;

	if (!is_ntfs_stream_smb_fname(smb_fname)) {
		return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
	}

	/* If the default stream is requested, just open the base file. */
	if (is_ntfs_default_stream_smb_fname(smb_fname)) {
		struct smb_filename *smb_fname_base = NULL;

		smb_fname_base = cp_smb_filename(talloc_tos(), smb_fname);
		if (smb_fname_base == NULL) {
			errno = ENOMEM;
			return -1;
		}

		ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_base);

		TALLOC_FREE(smb_fname_base);
		return ret;
	}

	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;
	}

	ret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname, xattr_name);

	if ((ret == -1) && (errno == ENOATTR)) {
		errno = ENOENT;
		goto fail;
	}

	ret = 0;

 fail:
	TALLOC_FREE(xattr_name);
	return ret;
}
Esempio n. 4
0
static int streams_xattr_lstat(vfs_handle_struct *handle,
			       struct smb_filename *smb_fname)
{
	NTSTATUS status;
	int result = -1;
	char *xattr_name = NULL;

	if (!is_ntfs_stream_smb_fname(smb_fname)) {
		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
	}

	/* If the default stream is requested, just stat the base file. */
	if (is_ntfs_default_stream_smb_fname(smb_fname)) {
		return streams_xattr_stat_base(handle, smb_fname, false);
	}

	/* Populate the stat struct with info from the base file. */
	if (streams_xattr_stat_base(handle, sm
Esempio n. 5
0
static int streams_xattr_rename(vfs_handle_struct *handle,
				const struct smb_filename *smb_fname_src,
				const struct smb_filename *smb_fname_dst)
{
	NTSTATUS status;
	int ret = -1;
	char *src_xattr_name = NULL;
	char *dst_xattr_name = NULL;
	bool src_is_stream, dst_is_stream;
	ssize_t oret;
	ssize_t nret;
	struct ea_struct ea;

	src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
	dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);

	if (!src_is_stream && !dst_is_stream) {
		return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
					   smb_fname_dst);
	}

	/* For now don't allow renames from or to the default stream. */
	if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
	    is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
		errno = ENOSYS;
		goto done;
	}

	/* Don't rename if the streams are identical. */
	if (strcasecmp_m(smb_fname_src->stream_name,
		       smb_fname_dst->stream_name) == 0) {
		goto done;
	}

	/* Get the xattr names. */
	status = streams_xattr_get_name(handle, talloc_tos(),
					smb_fname_src->stream_name,
					&src_xattr_name);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		goto fail;
	}
	status = streams_xattr_get_name(handle, talloc_tos(),
					smb_fname_dst->stream_name,
					&dst_xattr_name);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		goto fail;
	}

	/* read the old stream */
	status = get_ea_value(talloc_tos(), handle->conn, NULL,
			      smb_fname_src, src_xattr_name, &ea);
	if (!NT_STATUS_IS_OK(status)) {
		errno = ENOENT;
		goto fail;
	}

	/* (over)write the new stream */
	nret = SMB_VFS_SETXATTR(handle->conn, smb_fname_src,
				dst_xattr_name, ea.value.data, ea.value.length,
				0);
	if (nret < 0) {
		if (errno == ENOATTR) {
			errno = ENOENT;
		}
		goto fail;
	}

	/* remove the old stream */
	oret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname_src,
				   src_xattr_name);
	if (oret < 0) {
		if (errno == ENOATTR) {
			errno = ENOENT;
		}
		goto fail;
	}

 done:
	errno = 0;
	ret = 0;
 fail:
	TALLOC_FREE(src_xattr_name);
	TALLOC_FREE(dst_xattr_name);
	return ret;
}
Esempio n. 6
0
static int streams_xattr_open(vfs_handle_struct *handle,
			      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;
	int ret;

	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_ntfs_stream_smb_fname(smb_fname)) {
		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
	}

	/* If the default stream is requested, just open the base file. */
	if (is_ntfs_default_stream_smb_fname(smb_fname)) {
		char *tmp_stream_name;

		tmp_stream_name = smb_fname->stream_name;
		smb_fname->stream_name = NULL;

		ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);

		smb_fname->stream_name = tmp_stream_name;

		return ret;
	}

	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;
	}

	/*
	 * 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];

	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)
	    && !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.
		 */
		DEBUG(10, ("streams_xattr_open: base file %s not around, "
			   "returning ENOENT\n", smb_fname->base_name));
		errno = ENOENT;
		goto fail;
	}

	if ((!NT_STATUS_IS_OK(status) && (flags & O_CREAT)) ||
	    (flags & O_TRUNC)) {
		/*
		 * 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;
		}
	}

        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);
	/*
	 * 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);
	sio->fsp_name_ptr = fsp->fsp_name;
	sio->handle = handle;
	sio->fsp = fsp;

	if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
		errno = ENOMEM;
		goto fail;
	}

	return fakefd;

 fail:
	if (fakefd >= 0) {
		close(fakefd);
		fakefd = -1;
	}

	return -1;
}
Esempio n. 7
0
int onefs_rename(vfs_handle_struct *handle,
		 const struct smb_filename *smb_fname_src,
		 const struct smb_filename *smb_fname_dst)
{
	struct smb_filename *smb_fname_src_onefs = NULL;
	struct smb_filename *smb_fname_dst_onefs = NULL;
	NTSTATUS status;
	int saved_errno;
	int dir_fd = -1;
	int ret = -1;

	START_PROFILE(syscall_rename_at);

	if (!is_ntfs_stream_smb_fname(smb_fname_src) &&
	    !is_ntfs_stream_smb_fname(smb_fname_dst)) {
		ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
					  smb_fname_dst);
		goto done;
	}

	/* For now don't allow renames from or to the default stream. */
	if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
	    is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
		DEBUG(3, ("Unable to rename to/from a default stream: %s -> "
			  "%s\n", smb_fname_str_dbg(smb_fname_src),
			  smb_fname_str_dbg(smb_fname_dst)));
		errno = ENOSYS;
		goto done;
	}

	/* prep stream smb_filename structs. */
	status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_src,
					     &smb_fname_src_onefs);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		goto done;
	}
	status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_dst,
					     &smb_fname_dst_onefs);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		goto done;
	}

	dir_fd = get_stream_dir_fd(handle->conn, smb_fname_src->base_name,
				   NULL);
	if (dir_fd < -1) {
		goto done;
	}

	DEBUG(8, ("onefs_rename called for %s => %s\n",
		  smb_fname_str_dbg(smb_fname_src_onefs),
		  smb_fname_str_dbg(smb_fname_dst_onefs)));

	/* Handle rename of stream to default stream specially. */
	if (smb_fname_dst_onefs->stream_name == NULL) {
		ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name,
				   ENC_DEFAULT, AT_FDCWD,
				   smb_fname_dst_onefs->base_name,
				   ENC_DEFAULT);
	} else {
		ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name,
				   ENC_DEFAULT, dir_fd,
				   smb_fname_dst_onefs->stream_name,
				   ENC_DEFAULT);
	}

 done:
	END_PROFILE(syscall_rename_at);
	TALLOC_FREE(smb_fname_src_onefs);
	TALLOC_FREE(smb_fname_dst_onefs);

	saved_errno = errno;
	if (dir_fd >= 0) {
		close(dir_fd);
	}
	errno = saved_errno;
	return ret;
}