2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Volker Lendecke, 2007
5 * Copyright (C) Andrew Bartlett, 2012
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "source3/lib/xattr_tdb.h"
27 #include "lib/util/tevent_unix.h"
30 #define DBGC_CLASS DBGC_VFS
32 static bool xattr_tdb_init(int snum
, TALLOC_CTX
*mem_ctx
, struct db_context
**p_db
);
34 static int xattr_tdb_get_file_id(struct vfs_handle_struct
*handle
,
35 const char *path
, struct file_id
*id
)
38 TALLOC_CTX
*frame
= talloc_stackframe();
39 struct smb_filename
*smb_fname
;
41 smb_fname
= synthetic_smb_fname(frame
,
47 if (smb_fname
== NULL
) {
53 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
60 *id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &smb_fname
->st
);
65 static ssize_t
xattr_tdb_getxattr(struct vfs_handle_struct
*handle
,
66 const struct smb_filename
*smb_fname
,
72 struct db_context
*db
;
76 TALLOC_CTX
*frame
= talloc_stackframe();
78 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
79 if (!xattr_tdb_init(-1, frame
, &db
))
81 TALLOC_FREE(frame
); return -1;
84 ret
= xattr_tdb_get_file_id(handle
, smb_fname
->base_name
, &id
);
90 xattr_size
= xattr_tdb_getattr(db
, frame
, &id
, name
, &blob
);
102 if (blob
.length
> size
) {
107 memcpy(value
, blob
.data
, xattr_size
);
112 struct xattr_tdb_getxattrat_state
{
113 struct vfs_aio_state vfs_aio_state
;
115 uint8_t *xattr_value
;
118 static struct tevent_req
*xattr_tdb_getxattrat_send(
120 struct tevent_context
*ev
,
121 struct vfs_handle_struct
*handle
,
122 files_struct
*dir_fsp
,
123 const struct smb_filename
*smb_fname
,
124 const char *xattr_name
,
127 struct tevent_req
*req
= NULL
;
128 struct xattr_tdb_getxattrat_state
*state
= NULL
;
129 struct smb_filename
*cwd
= NULL
;
130 struct db_context
*db
= NULL
;
135 DATA_BLOB xattr_blob
;
137 req
= tevent_req_create(mem_ctx
, &state
,
138 struct xattr_tdb_getxattrat_state
);
142 state
->xattr_size
= -1;
144 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
145 if (!xattr_tdb_init(-1, state
, &db
)) {
146 tevent_req_error(req
, EIO
);
147 return tevent_req_post(req
, ev
);
150 cwd
= SMB_VFS_GETWD(dir_fsp
->conn
, state
);
151 if (tevent_req_nomem(cwd
, req
)) {
152 return tevent_req_post(req
, ev
);
155 ret
= SMB_VFS_CHDIR(dir_fsp
->conn
, dir_fsp
->fsp_name
);
157 tevent_req_error(req
, errno
);
158 return tevent_req_post(req
, ev
);
161 ret
= xattr_tdb_get_file_id(handle
, smb_fname
->base_name
, &id
);
164 cwd_ret
= SMB_VFS_CHDIR(dir_fsp
->conn
, cwd
);
165 SMB_ASSERT(cwd_ret
== 0);
168 tevent_req_error(req
, error
);
169 return tevent_req_post(req
, ev
);
172 state
->xattr_size
= xattr_tdb_getattr(db
,
177 if (state
->xattr_size
== -1) {
178 tevent_req_error(req
, errno
);
179 return tevent_req_post(req
, ev
);
182 if (alloc_hint
== 0) {
184 * The caller only wants to know the size.
186 tevent_req_done(req
);
187 return tevent_req_post(req
, ev
);
190 if (state
->xattr_size
== 0) {
194 tevent_req_done(req
);
195 return tevent_req_post(req
, ev
);
198 if (xattr_blob
.length
> alloc_hint
) {
200 * The data doesn't fit.
202 state
->xattr_size
= -1;
203 tevent_req_error(req
, ERANGE
);
204 return tevent_req_post(req
, ev
);
208 * take the whole blob.
210 state
->xattr_value
= xattr_blob
.data
;
212 tevent_req_done(req
);
213 return tevent_req_post(req
, ev
);
216 static ssize_t
xattr_tdb_getxattrat_recv(struct tevent_req
*req
,
217 struct vfs_aio_state
*aio_state
,
219 uint8_t **xattr_value
)
221 struct xattr_tdb_getxattrat_state
*state
= tevent_req_data(
222 req
, struct xattr_tdb_getxattrat_state
);
225 if (tevent_req_is_unix_error(req
, &aio_state
->error
)) {
226 tevent_req_received(req
);
230 *aio_state
= state
->vfs_aio_state
;
231 xattr_size
= state
->xattr_size
;
232 if (xattr_value
!= NULL
) {
233 *xattr_value
= talloc_move(mem_ctx
, &state
->xattr_value
);
236 tevent_req_received(req
);
240 static ssize_t
xattr_tdb_fgetxattr(struct vfs_handle_struct
*handle
,
241 struct files_struct
*fsp
,
242 const char *name
, void *value
, size_t size
)
244 SMB_STRUCT_STAT sbuf
;
246 struct db_context
*db
;
249 TALLOC_CTX
*frame
= talloc_stackframe();
251 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
252 if (!xattr_tdb_init(-1, frame
, &db
))
254 TALLOC_FREE(frame
); return -1;
257 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
262 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
264 xattr_size
= xattr_tdb_getattr(db
, frame
, &id
, name
, &blob
);
265 if (xattr_size
< 0) {
276 if (blob
.length
> size
) {
281 memcpy(value
, blob
.data
, xattr_size
);
286 static int xattr_tdb_setxattr(struct vfs_handle_struct
*handle
,
287 const struct smb_filename
*smb_fname
,
294 struct db_context
*db
;
296 TALLOC_CTX
*frame
= talloc_stackframe();
298 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
299 if (!xattr_tdb_init(-1, frame
, &db
))
301 TALLOC_FREE(frame
); return -1;
304 ret
= xattr_tdb_get_file_id(handle
, smb_fname
->base_name
, &id
);
310 ret
= xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
315 static int xattr_tdb_fsetxattr(struct vfs_handle_struct
*handle
,
316 struct files_struct
*fsp
,
317 const char *name
, const void *value
,
318 size_t size
, int flags
)
320 SMB_STRUCT_STAT sbuf
;
322 struct db_context
*db
;
324 TALLOC_CTX
*frame
= talloc_stackframe();
326 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
327 if (!xattr_tdb_init(-1, frame
, &db
))
329 TALLOC_FREE(frame
); return -1;
332 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
337 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
339 ret
= xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
345 static ssize_t
xattr_tdb_listxattr(struct vfs_handle_struct
*handle
,
346 const struct smb_filename
*smb_fname
,
351 struct db_context
*db
;
353 TALLOC_CTX
*frame
= talloc_stackframe();
355 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
356 if (!xattr_tdb_init(-1, frame
, &db
))
358 TALLOC_FREE(frame
); return -1;
361 ret
= xattr_tdb_get_file_id(handle
, smb_fname
->base_name
, &id
);
367 ret
= xattr_tdb_listattr(db
, &id
, list
, size
);
373 static ssize_t
xattr_tdb_flistxattr(struct vfs_handle_struct
*handle
,
374 struct files_struct
*fsp
, char *list
,
377 SMB_STRUCT_STAT sbuf
;
379 struct db_context
*db
;
381 TALLOC_CTX
*frame
= talloc_stackframe();
383 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
384 if (!xattr_tdb_init(-1, frame
, &db
))
386 TALLOC_FREE(frame
); return -1;
389 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
394 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
396 ret
= xattr_tdb_listattr(db
, &id
, list
, size
);
401 static int xattr_tdb_removexattr(struct vfs_handle_struct
*handle
,
402 const struct smb_filename
*smb_fname
,
406 struct db_context
*db
;
408 TALLOC_CTX
*frame
= talloc_stackframe();
410 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
411 if (!xattr_tdb_init(-1, frame
, &db
))
413 TALLOC_FREE(frame
); return -1;
416 ret
= xattr_tdb_get_file_id(handle
, smb_fname
->base_name
, &id
);
423 ret
= xattr_tdb_removeattr(db
, &id
, name
);
428 static int xattr_tdb_fremovexattr(struct vfs_handle_struct
*handle
,
429 struct files_struct
*fsp
, const char *name
)
431 SMB_STRUCT_STAT sbuf
;
433 struct db_context
*db
;
435 TALLOC_CTX
*frame
= talloc_stackframe();
437 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
438 if (!xattr_tdb_init(-1, frame
, &db
))
440 TALLOC_FREE(frame
); return -1;
443 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
448 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
450 ret
= xattr_tdb_removeattr(db
, &id
, name
);
456 * Open the tdb file upon VFS_CONNECT
459 static bool xattr_tdb_init(int snum
, TALLOC_CTX
*mem_ctx
, struct db_context
**p_db
)
461 struct db_context
*db
;
465 def_dbname
= state_path(talloc_tos(), "xattr.tdb");
466 if (def_dbname
== NULL
) {
471 dbname
= lp_parm_const_string(snum
, "xattr_tdb", "file", def_dbname
);
473 /* now we know dbname is not NULL */
476 db
= db_open(NULL
, dbname
, 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600,
477 DBWRAP_LOCK_ORDER_2
, DBWRAP_FLAG_NONE
);
486 TALLOC_FREE(def_dbname
);
491 TALLOC_FREE(def_dbname
);
495 static int xattr_tdb_openat(struct vfs_handle_struct
*handle
,
496 const struct files_struct
*dirfsp
,
497 const struct smb_filename
*smb_fname
,
498 struct files_struct
*fsp
,
502 struct db_context
*db
= NULL
;
503 TALLOC_CTX
*frame
= NULL
;
504 SMB_STRUCT_STAT sbuf
;
507 fsp
->fh
->fd
= SMB_VFS_NEXT_OPENAT(handle
,
514 if (fsp
->fh
->fd
< 0) {
518 if ((flags
& (O_CREAT
|O_EXCL
)) != (O_CREAT
|O_EXCL
)) {
523 * We know we used O_CREAT|O_EXCL and it worked.
524 * We must have created the file.
527 ret
= SMB_VFS_FSTAT(fsp
, &sbuf
);
529 /* Can't happen... */
530 DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
531 smb_fname_str_dbg(smb_fname
),
536 fsp
->file_id
= SMB_VFS_FILE_ID_CREATE(fsp
->conn
, &sbuf
);
538 frame
= talloc_stackframe();
540 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
541 if (!xattr_tdb_init(-1, frame
, &db
))
543 TALLOC_FREE(frame
); return -1;
546 xattr_tdb_remove_all_attrs(db
, &fsp
->file_id
);
552 static int xattr_tdb_mkdirat(vfs_handle_struct
*handle
,
553 struct files_struct
*dirfsp
,
554 const struct smb_filename
*smb_fname
,
557 struct db_context
*db
= NULL
;
558 TALLOC_CTX
*frame
= NULL
;
559 struct file_id fileid
;
561 struct smb_filename
*smb_fname_tmp
= NULL
;
563 ret
= SMB_VFS_NEXT_MKDIRAT(handle
,
571 frame
= talloc_stackframe();
572 smb_fname_tmp
= cp_smb_filename(frame
, smb_fname
);
573 if (smb_fname_tmp
== NULL
) {
579 /* Always use LSTAT here - we just creaded the directory. */
580 ret
= SMB_VFS_LSTAT(handle
->conn
, smb_fname_tmp
);
582 /* Rename race. Let upper level take care of it. */
586 if (!S_ISDIR(smb_fname_tmp
->st
.st_ex_mode
)) {
587 /* Rename race. Let upper level take care of it. */
592 fileid
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &smb_fname_tmp
->st
);
594 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
595 if (!xattr_tdb_init(-1, frame
, &db
))
597 TALLOC_FREE(frame
); return -1;
600 xattr_tdb_remove_all_attrs(db
, &fileid
);
606 * On unlink we need to delete the tdb record
608 static int xattr_tdb_unlinkat(vfs_handle_struct
*handle
,
609 struct files_struct
*dirfsp
,
610 const struct smb_filename
*smb_fname
,
613 struct smb_filename
*smb_fname_tmp
= NULL
;
615 struct db_context
*db
;
617 bool remove_record
= false;
618 TALLOC_CTX
*frame
= talloc_stackframe();
620 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
621 if (!xattr_tdb_init(-1, frame
, &db
))
623 TALLOC_FREE(frame
); return -1;
626 smb_fname_tmp
= cp_smb_filename(frame
, smb_fname
);
627 if (smb_fname_tmp
== NULL
) {
633 if (smb_fname_tmp
->flags
& SMB_FILENAME_POSIX_PATH
) {
634 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname_tmp
);
636 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname_tmp
);
642 if (flags
& AT_REMOVEDIR
) {
643 /* Always remove record when removing a directory succeeds. */
644 remove_record
= true;
646 if (smb_fname_tmp
->st
.st_ex_nlink
== 1) {
647 /* Only remove record on last link to file. */
648 remove_record
= true;
652 ret
= SMB_VFS_NEXT_UNLINKAT(handle
,
661 if (!remove_record
) {
665 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &smb_fname_tmp
->st
);
667 xattr_tdb_remove_all_attrs(db
, &id
);
675 * Destructor for the VFS private data
678 static void close_xattr_db(void **data
)
680 struct db_context
**p_db
= (struct db_context
**)data
;
684 static int xattr_tdb_connect(vfs_handle_struct
*handle
, const char *service
,
689 struct db_context
*db
;
691 res
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
696 snum
= find_service(talloc_tos(), service
, &sname
);
697 if (snum
== -1 || sname
== NULL
) {
699 * Should not happen, but we should not fail just *here*.
704 if (!xattr_tdb_init(snum
, NULL
, &db
)) {
705 DEBUG(5, ("Could not init xattr tdb\n"));
706 lp_do_parameter(snum
, "ea support", "False");
710 lp_do_parameter(snum
, "ea support", "True");
712 SMB_VFS_HANDLE_SET_DATA(handle
, db
, close_xattr_db
,
713 struct db_context
, return -1);
718 static struct vfs_fn_pointers vfs_xattr_tdb_fns
= {
719 .getxattr_fn
= xattr_tdb_getxattr
,
720 .getxattrat_send_fn
= xattr_tdb_getxattrat_send
,
721 .getxattrat_recv_fn
= xattr_tdb_getxattrat_recv
,
722 .fgetxattr_fn
= xattr_tdb_fgetxattr
,
723 .setxattr_fn
= xattr_tdb_setxattr
,
724 .fsetxattr_fn
= xattr_tdb_fsetxattr
,
725 .listxattr_fn
= xattr_tdb_listxattr
,
726 .flistxattr_fn
= xattr_tdb_flistxattr
,
727 .removexattr_fn
= xattr_tdb_removexattr
,
728 .fremovexattr_fn
= xattr_tdb_fremovexattr
,
729 .openat_fn
= xattr_tdb_openat
,
730 .mkdirat_fn
= xattr_tdb_mkdirat
,
731 .unlinkat_fn
= xattr_tdb_unlinkat
,
732 .connect_fn
= xattr_tdb_connect
,
736 NTSTATUS
vfs_xattr_tdb_init(TALLOC_CTX
*ctx
)
738 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "xattr_tdb",