2 * Store streams in xattrs
4 * Copyright (C) Volker Lendecke, 2008
6 * Partly based on James Peach's Darwin module, which is
8 * Copyright (C) James Peach 2006-2007
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
27 #include "../lib/crypto/md5.h"
30 #define DBGC_CLASS DBGC_VFS
32 struct streams_xattr_config
{
35 bool store_stream_type
;
43 vfs_handle_struct
*handle
;
46 static SMB_INO_T
stream_inode(const SMB_STRUCT_STAT
*sbuf
, const char *sname
)
49 unsigned char hash
[16];
53 DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
54 (unsigned long)sbuf
->st_ex_dev
,
55 (unsigned long)sbuf
->st_ex_ino
, sname
));
57 upper_sname
= talloc_strdup_upper(talloc_tos(), sname
);
58 SMB_ASSERT(upper_sname
!= NULL
);
61 MD5Update(&ctx
, (const unsigned char *)&(sbuf
->st_ex_dev
),
62 sizeof(sbuf
->st_ex_dev
));
63 MD5Update(&ctx
, (const unsigned char *)&(sbuf
->st_ex_ino
),
64 sizeof(sbuf
->st_ex_ino
));
65 MD5Update(&ctx
, (unsigned char *)upper_sname
,
66 talloc_get_size(upper_sname
)-1);
69 TALLOC_FREE(upper_sname
);
71 /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
72 memcpy(&result
, hash
, sizeof(result
));
74 DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result
));
79 static ssize_t
get_xattr_size(connection_struct
*conn
,
82 const char *xattr_name
)
88 status
= get_ea_value(talloc_tos(), conn
, fsp
, fname
,
91 if (!NT_STATUS_IS_OK(status
)) {
95 result
= ea
.value
.length
-1;
96 TALLOC_FREE(ea
.value
.data
);
101 * Given a stream name, populate xattr_name with the xattr name to use for
102 * accessing the stream.
104 static NTSTATUS
streams_xattr_get_name(vfs_handle_struct
*handle
,
106 const char *stream_name
,
110 struct streams_xattr_config
*config
;
112 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct streams_xattr_config
,
113 return NT_STATUS_UNSUCCESSFUL
);
115 stype
= strchr_m(stream_name
+ 1, ':');
117 *xattr_name
= talloc_asprintf(ctx
, "%s%s",
120 if (*xattr_name
== NULL
) {
121 return NT_STATUS_NO_MEMORY
;
125 /* Normalize the stream type to upercase. */
126 if (!strupper_m(strrchr_m(*xattr_name
, ':') + 1)) {
127 return NT_STATUS_INVALID_PARAMETER
;
129 } else if (config
->store_stream_type
) {
131 * Append an explicit stream type if one wasn't
134 *xattr_name
= talloc_asprintf(ctx
, "%s%s",
135 *xattr_name
, ":$DATA");
136 if (*xattr_name
== NULL
) {
137 return NT_STATUS_NO_MEMORY
;
141 DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name
,
147 static bool streams_xattr_recheck(struct stream_io
*sio
)
150 char *xattr_name
= NULL
;
152 if (sio
->fsp
->fsp_name
== sio
->fsp_name_ptr
) {
156 if (sio
->fsp
->fsp_name
->stream_name
== NULL
) {
157 /* how can this happen */
162 status
= streams_xattr_get_name(sio
->handle
, talloc_tos(),
163 sio
->fsp
->fsp_name
->stream_name
,
165 if (!NT_STATUS_IS_OK(status
)) {
169 TALLOC_FREE(sio
->xattr_name
);
170 TALLOC_FREE(sio
->base
);
171 sio
->xattr_name
= talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio
->handle
, sio
->fsp
),
173 sio
->base
= talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio
->handle
, sio
->fsp
),
174 sio
->fsp
->fsp_name
->base_name
);
175 sio
->fsp_name_ptr
= sio
->fsp
->fsp_name
;
177 TALLOC_FREE(xattr_name
);
179 if ((sio
->xattr_name
== NULL
) || (sio
->base
== NULL
)) {
187 * Helper to stat/lstat the base file of an smb_fname.
189 static int streams_xattr_stat_base(vfs_handle_struct
*handle
,
190 struct smb_filename
*smb_fname
,
193 char *tmp_stream_name
;
196 tmp_stream_name
= smb_fname
->stream_name
;
197 smb_fname
->stream_name
= NULL
;
199 result
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
201 result
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
203 smb_fname
->stream_name
= tmp_stream_name
;
207 static int streams_xattr_fstat(vfs_handle_struct
*handle
, files_struct
*fsp
,
208 SMB_STRUCT_STAT
*sbuf
)
210 struct smb_filename
*smb_fname_base
= NULL
;
212 struct stream_io
*io
= (struct stream_io
*)
213 VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
215 DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp
->fh
->fd
));
217 if (io
== NULL
|| fsp
->base_fsp
== NULL
) {
218 return SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
221 if (!streams_xattr_recheck(io
)) {
225 /* Create an smb_filename with stream_name == NULL. */
226 smb_fname_base
= synthetic_smb_fname(talloc_tos(), io
->base
,
228 if (smb_fname_base
== NULL
) {
233 if (lp_posix_pathnames()) {
234 ret
= SMB_VFS_LSTAT(handle
->conn
, smb_fname_base
);
236 ret
= SMB_VFS_STAT(handle
->conn
, smb_fname_base
);
238 *sbuf
= smb_fname_base
->st
;
239 TALLOC_FREE(smb_fname_base
);
245 sbuf
->st_ex_size
= get_xattr_size(handle
->conn
, fsp
->base_fsp
,
246 io
->base
, io
->xattr_name
);
247 if (sbuf
->st_ex_size
== -1) {
251 DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf
->st_ex_size
));
253 sbuf
->st_ex_ino
= stream_inode(sbuf
, io
->xattr_name
);
254 sbuf
->st_ex_mode
&= ~S_IFMT
;
255 sbuf
->st_ex_mode
|= S_IFREG
;
256 sbuf
->st_ex_blocks
= sbuf
->st_ex_size
/ STAT_ST_BLOCKSIZE
+ 1;
261 static int streams_xattr_stat(vfs_handle_struct
*handle
,
262 struct smb_filename
*smb_fname
)
266 char *xattr_name
= NULL
;
268 if (!is_ntfs_stream_smb_fname(smb_fname
)) {
269 return SMB_VFS_NEXT_STAT(handle
, smb_fname
);
272 /* Note if lp_posix_paths() is true, we can never
273 * get here as is_ntfs_stream_smb_fname() is
274 * always false. So we never need worry about
275 * not following links here. */
277 /* If the default stream is requested, just stat the base file. */
278 if (is_ntfs_default_stream_smb_fname(smb_fname
)) {
279 return streams_xattr_stat_base(handle
, smb_fname
, true);
282 /* Populate the stat struct with info from the base file. */
283 if (streams_xattr_stat_base(handle
, smb_fname
, true) == -1) {
287 /* Derive the xattr name to lookup. */
288 status
= streams_xattr_get_name(handle
, talloc_tos(),
289 smb_fname
->stream_name
, &xattr_name
);
290 if (!NT_STATUS_IS_OK(status
)) {
291 errno
= map_errno_from_nt_status(status
);
295 /* Augment the base file's stat information before returning. */
296 smb_fname
->st
.st_ex_size
= get_xattr_size(handle
->conn
, NULL
,
297 smb_fname
->base_name
,
299 if (smb_fname
->st
.st_ex_size
== -1) {
305 smb_fname
->st
.st_ex_ino
= stream_inode(&smb_fname
->st
, xattr_name
);
306 smb_fname
->st
.st_ex_mode
&= ~S_IFMT
;
307 smb_fname
->st
.st_ex_mode
|= S_IFREG
;
308 smb_fname
->st
.st_ex_blocks
=
309 smb_fname
->st
.st_ex_size
/ STAT_ST_BLOCKSIZE
+ 1;
313 TALLOC_FREE(xattr_name
);
317 static int streams_xattr_lstat(vfs_handle_struct
*handle
,
318 struct smb_filename
*smb_fname
)
322 char *xattr_name
= NULL
;
324 if (!is_ntfs_stream_smb_fname(smb_fname
)) {
325 return SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
328 /* If the default stream is requested, just stat the base file. */
329 if (is_ntfs_default_stream_smb_fname(smb_fname
)) {
330 return streams_xattr_stat_base(handle
, smb_fname
, false);
333 /* Populate the stat struct with info from the base file. */
334 if (streams_xattr_stat_base(handle
, smb_fname
, false) == -1) {
338 /* Derive the xattr name to lookup. */
339 status
= streams_xattr_get_name(handle
, talloc_tos(),
340 smb_fname
->stream_name
, &xattr_name
);
341 if (!NT_STATUS_IS_OK(status
)) {
342 errno
= map_errno_from_nt_status(status
);
346 /* Augment the base file's stat information before returning. */
347 smb_fname
->st
.st_ex_size
= get_xattr_size(handle
->conn
, NULL
,
348 smb_fname
->base_name
,
350 if (smb_fname
->st
.st_ex_size
== -1) {
356 smb_fname
->st
.st_ex_ino
= stream_inode(&smb_fname
->st
, xattr_name
);
357 smb_fname
->st
.st_ex_mode
&= ~S_IFMT
;
358 smb_fname
->st
.st_ex_mode
|= S_IFREG
;
359 smb_fname
->st
.st_ex_blocks
=
360 smb_fname
->st
.st_ex_size
/ STAT_ST_BLOCKSIZE
+ 1;
365 TALLOC_FREE(xattr_name
);
369 static int streams_xattr_open(vfs_handle_struct
*handle
,
370 struct smb_filename
*smb_fname
,
371 files_struct
*fsp
, int flags
, mode_t mode
)
374 struct smb_filename
*smb_fname_base
= NULL
;
375 struct stream_io
*sio
;
377 char *xattr_name
= NULL
;
381 DEBUG(10, ("streams_xattr_open called for %s with flags 0x%x\n",
382 smb_fname_str_dbg(smb_fname
), flags
));
384 if (!is_ntfs_stream_smb_fname(smb_fname
)) {
385 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
388 /* If the default stream is requested, just open the base file. */
389 if (is_ntfs_default_stream_smb_fname(smb_fname
)) {
390 char *tmp_stream_name
;
393 tmp_stream_name
= smb_fname
->stream_name
;
394 smb_fname
->stream_name
= NULL
;
396 ret
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
398 smb_fname
->stream_name
= tmp_stream_name
;
403 status
= streams_xattr_get_name(handle
, talloc_tos(),
404 smb_fname
->stream_name
, &xattr_name
);
405 if (!NT_STATUS_IS_OK(status
)) {
406 errno
= map_errno_from_nt_status(status
);
410 /* Create an smb_filename with stream_name == NULL. */
411 smb_fname_base
= synthetic_smb_fname(
412 talloc_tos(), smb_fname
->base_name
, NULL
, NULL
);
413 if (smb_fname_base
== NULL
) {
419 * We use baseflags to turn off nasty side-effects when opening the
423 baseflags
&= ~O_TRUNC
;
424 baseflags
&= ~O_EXCL
;
425 baseflags
&= ~O_CREAT
;
427 hostfd
= SMB_VFS_OPEN(handle
->conn
, smb_fname_base
, fsp
,
430 TALLOC_FREE(smb_fname_base
);
432 /* It is legit to open a stream on a directory, but the base
433 * fd has to be read-only.
435 if ((hostfd
== -1) && (errno
== EISDIR
)) {
436 baseflags
&= ~O_ACCMODE
;
437 baseflags
|= O_RDONLY
;
438 hostfd
= SMB_VFS_OPEN(handle
->conn
, smb_fname
, fsp
, baseflags
,
446 status
= get_ea_value(talloc_tos(), handle
->conn
, NULL
,
447 smb_fname
->base_name
, xattr_name
, &ea
);
449 DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status
)));
451 if (!NT_STATUS_IS_OK(status
)
452 && !NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
454 * The base file is not there. This is an error even if we got
455 * O_CREAT, the higher levels should have created the base
458 DEBUG(10, ("streams_xattr_open: base file %s not around, "
459 "returning ENOENT\n", smb_fname
->base_name
));
464 if ((!NT_STATUS_IS_OK(status
) && (flags
& O_CREAT
)) ||
467 * The attribute does not exist or needs to be truncated
471 * Darn, xattrs need at least 1 byte
475 DEBUG(10, ("creating or truncating attribute %s on file %s\n",
476 xattr_name
, smb_fname
->base_name
));
478 if (fsp
->base_fsp
->fh
->fd
!= -1) {
479 if (SMB_VFS_FSETXATTR(
480 fsp
->base_fsp
, xattr_name
,
482 flags
& O_EXCL
? XATTR_CREATE
: 0) == -1) {
486 if (SMB_VFS_SETXATTR(
487 handle
->conn
, smb_fname
->base_name
,
488 xattr_name
, &null
, sizeof(null
),
489 flags
& O_EXCL
? XATTR_CREATE
: 0) == -1) {
495 sio
= (struct stream_io
*)VFS_ADD_FSP_EXTENSION(handle
, fsp
,
503 sio
->xattr_name
= talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle
, fsp
),
505 sio
->base
= talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle
, fsp
),
506 smb_fname
->base_name
);
507 sio
->fsp_name_ptr
= fsp
->fsp_name
;
508 sio
->handle
= handle
;
511 if ((sio
->xattr_name
== NULL
) || (sio
->base
== NULL
)) {
521 * BUGBUGBUG -- we would need to call fd_close_posix here, but
522 * we don't have a full fsp yet
524 fsp
->fh
->fd
= hostfd
;
531 static int streams_xattr_unlink(vfs_handle_struct
*handle
,
532 const struct smb_filename
*smb_fname
)
538 if (!is_ntfs_stream_smb_fname(smb_fname
)) {
539 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
542 /* If the default stream is requested, just open the base file. */
543 if (is_ntfs_default_stream_smb_fname(smb_fname
)) {
544 struct smb_filename
*smb_fname_base
= NULL
;
546 smb_fname_base
= cp_smb_filename(talloc_tos(), smb_fname
);
547 if (smb_fname_base
== NULL
) {
552 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname_base
);
554 TALLOC_FREE(smb_fname_base
);
558 status
= streams_xattr_get_name(handle
, talloc_tos(),
559 smb_fname
->stream_name
, &xattr_name
);
560 if (!NT_STATUS_IS_OK(status
)) {
561 errno
= map_errno_from_nt_status(status
);
565 ret
= SMB_VFS_REMOVEXATTR(handle
->conn
, smb_fname
->base_name
, xattr_name
);
567 if ((ret
== -1) && (errno
== ENOATTR
)) {
575 TALLOC_FREE(xattr_name
);
579 static int streams_xattr_rename(vfs_handle_struct
*handle
,
580 const struct smb_filename
*smb_fname_src
,
581 const struct smb_filename
*smb_fname_dst
)
585 char *src_xattr_name
= NULL
;
586 char *dst_xattr_name
= NULL
;
587 bool src_is_stream
, dst_is_stream
;
592 src_is_stream
= is_ntfs_stream_smb_fname(smb_fname_src
);
593 dst_is_stream
= is_ntfs_stream_smb_fname(smb_fname_dst
);
595 if (!src_is_stream
&& !dst_is_stream
) {
596 return SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
,
600 /* For now don't allow renames from or to the default stream. */
601 if (is_ntfs_default_stream_smb_fname(smb_fname_src
) ||
602 is_ntfs_default_stream_smb_fname(smb_fname_dst
)) {
607 /* Don't rename if the streams are identical. */
608 if (strcasecmp_m(smb_fname_src
->stream_name
,
609 smb_fname_dst
->stream_name
) == 0) {
613 /* Get the xattr names. */
614 status
= streams_xattr_get_name(handle
, talloc_tos(),
615 smb_fname_src
->stream_name
,
617 if (!NT_STATUS_IS_OK(status
)) {
618 errno
= map_errno_from_nt_status(status
);
621 status
= streams_xattr_get_name(handle
, talloc_tos(),
622 smb_fname_dst
->stream_name
,
624 if (!NT_STATUS_IS_OK(status
)) {
625 errno
= map_errno_from_nt_status(status
);
629 /* read the old stream */
630 status
= get_ea_value(talloc_tos(), handle
->conn
, NULL
,
631 smb_fname_src
->base_name
, src_xattr_name
, &ea
);
632 if (!NT_STATUS_IS_OK(status
)) {
637 /* (over)write the new stream */
638 nret
= SMB_VFS_SETXATTR(handle
->conn
, smb_fname_src
->base_name
,
639 dst_xattr_name
, ea
.value
.data
, ea
.value
.length
,
642 if (errno
== ENOATTR
) {
648 /* remove the old stream */
649 oret
= SMB_VFS_REMOVEXATTR(handle
->conn
, smb_fname_src
->base_name
,
652 if (errno
== ENOATTR
) {
662 TALLOC_FREE(src_xattr_name
);
663 TALLOC_FREE(dst_xattr_name
);
667 static NTSTATUS
walk_xattr_streams(vfs_handle_struct
*handle
, files_struct
*fsp
,
669 bool (*fn
)(struct ea_struct
*ea
,
676 struct streams_xattr_config
*config
;
678 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct streams_xattr_config
,
679 return NT_STATUS_UNSUCCESSFUL
);
681 status
= get_ea_names_from_file(talloc_tos(), handle
->conn
, fsp
, fname
,
683 if (!NT_STATUS_IS_OK(status
)) {
687 for (i
=0; i
<num_names
; i
++) {
690 if (strncmp(names
[i
], config
->prefix
,
691 config
->prefix_len
) != 0) {
694 if (samba_private_attr_name(names
[i
])) {
698 status
= get_ea_value(names
, handle
->conn
, fsp
, fname
,
700 if (!NT_STATUS_IS_OK(status
)) {
701 DEBUG(10, ("Could not get ea %s for file %s: %s\n",
702 names
[i
], fname
, nt_errstr(status
)));
706 ea
.name
= talloc_asprintf(
707 ea
.value
.data
, ":%s%s",
708 names
[i
] + config
->prefix_len
,
709 config
->store_stream_type
? "" : ":$DATA");
710 if (ea
.name
== NULL
) {
711 DEBUG(0, ("talloc failed\n"));
715 if (!fn(&ea
, private_data
)) {
716 TALLOC_FREE(ea
.value
.data
);
720 TALLOC_FREE(ea
.value
.data
);
727 static bool add_one_stream(TALLOC_CTX
*mem_ctx
, unsigned int *num_streams
,
728 struct stream_struct
**streams
,
729 const char *name
, off_t size
,
732 struct stream_struct
*tmp
;
734 tmp
= talloc_realloc(mem_ctx
, *streams
, struct stream_struct
,
740 tmp
[*num_streams
].name
= talloc_strdup(tmp
, name
);
741 if (tmp
[*num_streams
].name
== NULL
) {
745 tmp
[*num_streams
].size
= size
;
746 tmp
[*num_streams
].alloc_size
= alloc_size
;
753 struct streaminfo_state
{
755 vfs_handle_struct
*handle
;
756 unsigned int num_streams
;
757 struct stream_struct
*streams
;
761 static bool collect_one_stream(struct ea_struct
*ea
, void *private_data
)
763 struct streaminfo_state
*state
=
764 (struct streaminfo_state
*)private_data
;
766 if (!add_one_stream(state
->mem_ctx
,
767 &state
->num_streams
, &state
->streams
,
768 ea
->name
, ea
->value
.length
-1,
769 smb_roundup(state
->handle
->conn
,
770 ea
->value
.length
-1))) {
771 state
->status
= NT_STATUS_NO_MEMORY
;
778 static NTSTATUS
streams_xattr_streaminfo(vfs_handle_struct
*handle
,
779 struct files_struct
*fsp
,
782 unsigned int *pnum_streams
,
783 struct stream_struct
**pstreams
)
785 SMB_STRUCT_STAT sbuf
;
788 struct streaminfo_state state
;
790 if ((fsp
!= NULL
) && (fsp
->fh
->fd
!= -1)) {
791 ret
= SMB_VFS_FSTAT(fsp
, &sbuf
);
794 struct smb_filename
*smb_fname
= NULL
;
795 smb_fname
= synthetic_smb_fname(talloc_tos(), fname
, NULL
,
797 if (smb_fname
== NULL
) {
798 return NT_STATUS_NO_MEMORY
;
800 if (lp_posix_pathnames()) {
801 ret
= SMB_VFS_LSTAT(handle
->conn
, smb_fname
);
803 ret
= SMB_VFS_STAT(handle
->conn
, smb_fname
);
805 sbuf
= smb_fname
->st
;
806 TALLOC_FREE(smb_fname
);
810 return map_nt_error_from_unix(errno
);
813 state
.streams
= *pstreams
;
814 state
.num_streams
= *pnum_streams
;
815 state
.mem_ctx
= mem_ctx
;
816 state
.handle
= handle
;
817 state
.status
= NT_STATUS_OK
;
819 if (S_ISLNK(sbuf
.st_ex_mode
)) {
821 * Currently we do't have SMB_VFS_LLISTXATTR
822 * inside the VFS which means there's no way
823 * to cope with a symlink when lp_posix_pathnames().
824 * returns true. For now ignore links.
825 * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
827 status
= NT_STATUS_OK
;
829 status
= walk_xattr_streams(handle
, fsp
, fname
,
830 collect_one_stream
, &state
);
833 if (!NT_STATUS_IS_OK(status
)) {
834 TALLOC_FREE(state
.streams
);
838 if (!NT_STATUS_IS_OK(state
.status
)) {
839 TALLOC_FREE(state
.streams
);
843 *pnum_streams
= state
.num_streams
;
844 *pstreams
= state
.streams
;
846 return SMB_VFS_NEXT_STREAMINFO(handle
, fsp
, fname
, mem_ctx
, pnum_streams
, pstreams
);
849 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct
*handle
,
850 enum timestamp_set_resolution
*p_ts_res
)
852 return SMB_VFS_NEXT_FS_CAPABILITIES(handle
, p_ts_res
) | FILE_NAMED_STREAMS
;
855 static int streams_xattr_connect(vfs_handle_struct
*handle
,
856 const char *service
, const char *user
)
858 struct streams_xattr_config
*config
;
859 const char *default_prefix
= SAMBA_XATTR_DOSSTREAM_PREFIX
;
862 config
= talloc_zero(handle
->conn
, struct streams_xattr_config
);
863 if (config
== NULL
) {
864 DEBUG(1, ("talloc_zero() failed\n"));
869 prefix
= lp_parm_const_string(SNUM(handle
->conn
),
870 "streams_xattr", "prefix",
872 config
->prefix
= talloc_strdup(config
, prefix
);
873 if (config
->prefix
== NULL
) {
874 DEBUG(1, ("talloc_strdup() failed\n"));
878 config
->prefix_len
= strlen(config
->prefix
);
879 DEBUG(10, ("streams_xattr using stream prefix: %s\n", config
->prefix
));
881 config
->store_stream_type
= lp_parm_bool(SNUM(handle
->conn
),
886 SMB_VFS_HANDLE_SET_DATA(handle
, config
,
887 NULL
, struct stream_xattr_config
,
893 static ssize_t
streams_xattr_pwrite(vfs_handle_struct
*handle
,
894 files_struct
*fsp
, const void *data
,
895 size_t n
, off_t offset
)
897 struct stream_io
*sio
=
898 (struct stream_io
*)VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
903 DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n
));
906 return SMB_VFS_NEXT_PWRITE(handle
, fsp
, data
, n
, offset
);
909 if (!streams_xattr_recheck(sio
)) {
913 status
= get_ea_value(talloc_tos(), handle
->conn
, fsp
->base_fsp
,
914 sio
->base
, sio
->xattr_name
, &ea
);
915 if (!NT_STATUS_IS_OK(status
)) {
919 if ((offset
+ n
) > ea
.value
.length
-1) {
922 tmp
= talloc_realloc(talloc_tos(), ea
.value
.data
, uint8
,
926 TALLOC_FREE(ea
.value
.data
);
931 ea
.value
.length
= offset
+ n
+ 1;
932 ea
.value
.data
[offset
+n
] = 0;
935 memcpy(ea
.value
.data
+ offset
, data
, n
);
937 if (fsp
->base_fsp
->fh
->fd
!= -1) {
938 ret
= SMB_VFS_FSETXATTR(fsp
->base_fsp
,
940 ea
.value
.data
, ea
.value
.length
, 0);
942 ret
= SMB_VFS_SETXATTR(fsp
->conn
,
943 fsp
->base_fsp
->fsp_name
->base_name
,
945 ea
.value
.data
, ea
.value
.length
, 0);
947 TALLOC_FREE(ea
.value
.data
);
956 static ssize_t
streams_xattr_pread(vfs_handle_struct
*handle
,
957 files_struct
*fsp
, void *data
,
958 size_t n
, off_t offset
)
960 struct stream_io
*sio
=
961 (struct stream_io
*)VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
964 size_t length
, overlap
;
966 DEBUG(10, ("streams_xattr_pread: offset=%d, size=%d\n",
967 (int)offset
, (int)n
));
970 return SMB_VFS_NEXT_PREAD(handle
, fsp
, data
, n
, offset
);
973 if (!streams_xattr_recheck(sio
)) {
977 status
= get_ea_value(talloc_tos(), handle
->conn
, fsp
->base_fsp
,
978 sio
->base
, sio
->xattr_name
, &ea
);
979 if (!NT_STATUS_IS_OK(status
)) {
983 length
= ea
.value
.length
-1;
985 DEBUG(10, ("streams_xattr_pread: get_ea_value returned %d bytes\n",
988 /* Attempt to read past EOF. */
989 if (length
<= offset
) {
993 overlap
= (offset
+ n
) > length
? (length
- offset
) : n
;
994 memcpy(data
, ea
.value
.data
+ offset
, overlap
);
996 TALLOC_FREE(ea
.value
.data
);
1000 static int streams_xattr_ftruncate(struct vfs_handle_struct
*handle
,
1001 struct files_struct
*fsp
,
1006 struct ea_struct ea
;
1008 struct stream_io
*sio
=
1009 (struct stream_io
*)VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
1011 DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
1012 fsp_str_dbg(fsp
), (double)offset
));
1015 return SMB_VFS_NEXT_FTRUNCATE(handle
, fsp
, offset
);
1018 if (!streams_xattr_recheck(sio
)) {
1022 status
= get_ea_value(talloc_tos(), handle
->conn
, fsp
->base_fsp
,
1023 sio
->base
, sio
->xattr_name
, &ea
);
1024 if (!NT_STATUS_IS_OK(status
)) {
1028 tmp
= talloc_realloc(talloc_tos(), ea
.value
.data
, uint8
,
1032 TALLOC_FREE(ea
.value
.data
);
1037 /* Did we expand ? */
1038 if (ea
.value
.length
< offset
+ 1) {
1039 memset(&tmp
[ea
.value
.length
], '\0',
1040 offset
+ 1 - ea
.value
.length
);
1043 ea
.value
.data
= tmp
;
1044 ea
.value
.length
= offset
+ 1;
1045 ea
.value
.data
[offset
] = 0;
1047 if (fsp
->base_fsp
->fh
->fd
!= -1) {
1048 ret
= SMB_VFS_FSETXATTR(fsp
->base_fsp
,
1050 ea
.value
.data
, ea
.value
.length
, 0);
1052 ret
= SMB_VFS_SETXATTR(fsp
->conn
,
1053 fsp
->base_fsp
->fsp_name
->base_name
,
1055 ea
.value
.data
, ea
.value
.length
, 0);
1058 TALLOC_FREE(ea
.value
.data
);
1067 static int streams_xattr_fallocate(struct vfs_handle_struct
*handle
,
1068 struct files_struct
*fsp
,
1069 enum vfs_fallocate_mode mode
,
1073 struct stream_io
*sio
=
1074 (struct stream_io
*)VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
1076 DEBUG(10, ("streams_xattr_fallocate called for file %s offset %.0f"
1078 fsp_str_dbg(fsp
), (double)offset
, (double)len
));
1081 return SMB_VFS_NEXT_FALLOCATE(handle
, fsp
, mode
, offset
, len
);
1084 if (!streams_xattr_recheck(sio
)) {
1088 /* Let the pwrite code path handle it. */
1093 static struct vfs_fn_pointers vfs_streams_xattr_fns
= {
1094 .fs_capabilities_fn
= streams_xattr_fs_capabilities
,
1095 .connect_fn
= streams_xattr_connect
,
1096 .open_fn
= streams_xattr_open
,
1097 .stat_fn
= streams_xattr_stat
,
1098 .fstat_fn
= streams_xattr_fstat
,
1099 .lstat_fn
= streams_xattr_lstat
,
1100 .pread_fn
= streams_xattr_pread
,
1101 .pwrite_fn
= streams_xattr_pwrite
,
1102 .unlink_fn
= streams_xattr_unlink
,
1103 .rename_fn
= streams_xattr_rename
,
1104 .ftruncate_fn
= streams_xattr_ftruncate
,
1105 .fallocate_fn
= streams_xattr_fallocate
,
1106 .streaminfo_fn
= streams_xattr_streaminfo
,
1109 NTSTATUS
vfs_streams_xattr_init(void);
1110 NTSTATUS
vfs_streams_xattr_init(void)
1112 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "streams_xattr",
1113 &vfs_streams_xattr_fns
);