2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Volker Lendecke, 2007
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "librpc/gen_ndr/xattr.h"
22 #include "librpc/gen_ndr/ndr_xattr.h"
25 #define DBGC_CLASS DBGC_VFS
28 * unmarshall tdb_xattrs
31 static NTSTATUS
xattr_tdb_pull_attrs(TALLOC_CTX
*mem_ctx
,
33 struct tdb_xattrs
**presult
)
36 enum ndr_err_code ndr_err
;
37 struct tdb_xattrs
*result
;
39 if (!(result
= TALLOC_ZERO_P(mem_ctx
, struct tdb_xattrs
))) {
40 return NT_STATUS_NO_MEMORY
;
43 if (data
->dsize
== 0) {
48 blob
= data_blob_const(data
->dptr
, data
->dsize
);
50 ndr_err
= ndr_pull_struct_blob(
51 &blob
, result
, NULL
, result
,
52 (ndr_pull_flags_fn_t
)ndr_pull_tdb_xattrs
);
54 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
55 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
56 ndr_errstr(ndr_err
)));
58 return ndr_map_error2ntstatus(ndr_err
);;
69 static NTSTATUS
xattr_tdb_push_attrs(TALLOC_CTX
*mem_ctx
,
70 const struct tdb_xattrs
*attribs
,
74 enum ndr_err_code ndr_err
;
76 ndr_err
= ndr_push_struct_blob(
77 &blob
, mem_ctx
, NULL
, attribs
,
78 (ndr_push_flags_fn_t
)ndr_push_tdb_xattrs
);
80 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
81 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
82 ndr_errstr(ndr_err
)));
83 return ndr_map_error2ntstatus(ndr_err
);;
86 *data
= make_tdb_data(blob
.data
, blob
.length
);
91 * Load tdb_xattrs for a file from the tdb
94 static NTSTATUS
xattr_tdb_load_attrs(TALLOC_CTX
*mem_ctx
,
95 struct db_context
*db_ctx
,
96 const struct file_id
*id
,
97 struct tdb_xattrs
**presult
)
103 /* For backwards compatibility only store the dev/inode. */
104 push_file_id_16((char *)id_buf
, id
);
106 if (db_ctx
->fetch(db_ctx
, mem_ctx
,
107 make_tdb_data(id_buf
, sizeof(id_buf
)),
109 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
112 status
= xattr_tdb_pull_attrs(mem_ctx
, &data
, presult
);
113 TALLOC_FREE(data
.dptr
);
118 * fetch_lock the tdb_ea record for a file
121 static struct db_record
*xattr_tdb_lock_attrs(TALLOC_CTX
*mem_ctx
,
122 struct db_context
*db_ctx
,
123 const struct file_id
*id
)
127 /* For backwards compatibility only store the dev/inode. */
128 push_file_id_16((char *)id_buf
, id
);
129 return db_ctx
->fetch_locked(db_ctx
, mem_ctx
,
130 make_tdb_data(id_buf
, sizeof(id_buf
)));
134 * Save tdb_xattrs to a previously fetch_locked record
137 static NTSTATUS
xattr_tdb_save_attrs(struct db_record
*rec
,
138 const struct tdb_xattrs
*attribs
)
140 TDB_DATA data
= tdb_null
;
143 status
= xattr_tdb_push_attrs(talloc_tos(), attribs
, &data
);
145 if (!NT_STATUS_IS_OK(status
)) {
146 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
151 status
= rec
->store(rec
, data
, 0);
153 TALLOC_FREE(data
.dptr
);
159 * Worker routine for getxattr and fgetxattr
162 static ssize_t
xattr_tdb_getattr(struct db_context
*db_ctx
,
163 const struct file_id
*id
,
164 const char *name
, void *value
, size_t size
)
166 struct tdb_xattrs
*attribs
;
171 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
172 file_id_string_tos(id
), name
));
174 status
= xattr_tdb_load_attrs(talloc_tos(), db_ctx
, id
, &attribs
);
176 if (!NT_STATUS_IS_OK(status
)) {
177 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
183 for (i
=0; i
<attribs
->num_eas
; i
++) {
184 if (strcmp(attribs
->eas
[i
].name
, name
) == 0) {
189 if (i
== attribs
->num_eas
) {
194 if (attribs
->eas
[i
].value
.length
> size
) {
199 memcpy(value
, attribs
->eas
[i
].value
.data
,
200 attribs
->eas
[i
].value
.length
);
201 result
= attribs
->eas
[i
].value
.length
;
204 TALLOC_FREE(attribs
);
208 static ssize_t
xattr_tdb_getxattr(struct vfs_handle_struct
*handle
,
209 const char *path
, const char *name
,
210 void *value
, size_t size
)
212 SMB_STRUCT_STAT sbuf
;
214 struct db_context
*db
;
217 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
219 if (lp_posix_pathnames()) {
220 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
222 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
229 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
231 return xattr_tdb_getattr(db
, &id
, name
, value
, size
);
234 static ssize_t
xattr_tdb_fgetxattr(struct vfs_handle_struct
*handle
,
235 struct files_struct
*fsp
,
236 const char *name
, void *value
, size_t size
)
238 SMB_STRUCT_STAT sbuf
;
240 struct db_context
*db
;
242 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
244 if (SMB_VFS_FSTAT(fsp
, &sbuf
) == -1) {
248 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
250 return xattr_tdb_getattr(db
, &id
, name
, value
, size
);
254 * Worker routine for setxattr and fsetxattr
257 static int xattr_tdb_setattr(struct db_context
*db_ctx
,
258 const struct file_id
*id
, const char *name
,
259 const void *value
, size_t size
, int flags
)
262 struct db_record
*rec
;
263 struct tdb_xattrs
*attribs
;
266 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
267 file_id_string_tos(id
), name
));
269 rec
= xattr_tdb_lock_attrs(talloc_tos(), db_ctx
, id
);
272 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
277 status
= xattr_tdb_pull_attrs(rec
, &rec
->value
, &attribs
);
279 if (!NT_STATUS_IS_OK(status
)) {
280 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
286 for (i
=0; i
<attribs
->num_eas
; i
++) {
287 if (strcmp(attribs
->eas
[i
].name
, name
) == 0) {
288 if (flags
& XATTR_CREATE
) {
297 if (i
== attribs
->num_eas
) {
298 struct xattr_EA
*tmp
;
300 if (flags
& XATTR_REPLACE
) {
306 tmp
= TALLOC_REALLOC_ARRAY(
307 attribs
, attribs
->eas
, struct xattr_EA
,
308 attribs
->num_eas
+ 1);
311 DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
318 attribs
->num_eas
+= 1;
321 attribs
->eas
[i
].name
= name
;
322 attribs
->eas
[i
].value
.data
= CONST_DISCARD(uint8
*, value
);
323 attribs
->eas
[i
].value
.length
= size
;
325 status
= xattr_tdb_save_attrs(rec
, attribs
);
329 if (!NT_STATUS_IS_OK(status
)) {
330 DEBUG(1, ("save failed: %s\n", nt_errstr(status
)));
337 static int xattr_tdb_setxattr(struct vfs_handle_struct
*handle
,
338 const char *path
, const char *name
,
339 const void *value
, size_t size
, int flags
)
341 SMB_STRUCT_STAT sbuf
;
343 struct db_context
*db
;
346 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
348 if (lp_posix_pathnames()) {
349 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
351 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
358 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
360 return xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
363 static int xattr_tdb_fsetxattr(struct vfs_handle_struct
*handle
,
364 struct files_struct
*fsp
,
365 const char *name
, const void *value
,
366 size_t size
, int flags
)
368 SMB_STRUCT_STAT sbuf
;
370 struct db_context
*db
;
372 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
374 if (SMB_VFS_FSTAT(fsp
, &sbuf
) == -1) {
378 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
380 return xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
384 * Worker routine for listxattr and flistxattr
387 static ssize_t
xattr_tdb_listattr(struct db_context
*db_ctx
,
388 const struct file_id
*id
, char *list
,
392 struct tdb_xattrs
*attribs
;
396 status
= xattr_tdb_load_attrs(talloc_tos(), db_ctx
, id
, &attribs
);
398 if (!NT_STATUS_IS_OK(status
)) {
399 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
405 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
408 for (i
=0; i
<attribs
->num_eas
; i
++) {
411 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
412 attribs
->eas
[i
].name
));
414 tmp
= strlen(attribs
->eas
[i
].name
);
417 * Try to protect against overflow
420 if (len
+ (tmp
+1) < len
) {
421 TALLOC_FREE(attribs
);
427 * Take care of the terminating NULL
433 TALLOC_FREE(attribs
);
440 for (i
=0; i
<attribs
->num_eas
; i
++) {
441 strlcpy(list
+len
, attribs
->eas
[i
].name
,
443 len
+= (strlen(attribs
->eas
[i
].name
) + 1);
446 TALLOC_FREE(attribs
);
450 static ssize_t
xattr_tdb_listxattr(struct vfs_handle_struct
*handle
,
451 const char *path
, char *list
, size_t size
)
453 SMB_STRUCT_STAT sbuf
;
455 struct db_context
*db
;
458 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
460 if (lp_posix_pathnames()) {
461 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
463 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
470 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
472 return xattr_tdb_listattr(db
, &id
, list
, size
);
475 static ssize_t
xattr_tdb_flistxattr(struct vfs_handle_struct
*handle
,
476 struct files_struct
*fsp
, char *list
,
479 SMB_STRUCT_STAT sbuf
;
481 struct db_context
*db
;
483 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
485 if (SMB_VFS_FSTAT(fsp
, &sbuf
) == -1) {
489 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
491 return xattr_tdb_listattr(db
, &id
, list
, size
);
495 * Worker routine for removexattr and fremovexattr
498 static int xattr_tdb_removeattr(struct db_context
*db_ctx
,
499 const struct file_id
*id
, const char *name
)
502 struct db_record
*rec
;
503 struct tdb_xattrs
*attribs
;
506 rec
= xattr_tdb_lock_attrs(talloc_tos(), db_ctx
, id
);
509 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
514 status
= xattr_tdb_pull_attrs(rec
, &rec
->value
, &attribs
);
516 if (!NT_STATUS_IS_OK(status
)) {
517 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
523 for (i
=0; i
<attribs
->num_eas
; i
++) {
524 if (strcmp(attribs
->eas
[i
].name
, name
) == 0) {
529 if (i
== attribs
->num_eas
) {
536 attribs
->eas
[attribs
->num_eas
-1];
537 attribs
->num_eas
-= 1;
539 if (attribs
->num_eas
== 0) {
540 rec
->delete_rec(rec
);
545 status
= xattr_tdb_save_attrs(rec
, attribs
);
549 if (!NT_STATUS_IS_OK(status
)) {
550 DEBUG(1, ("save failed: %s\n", nt_errstr(status
)));
557 static int xattr_tdb_removexattr(struct vfs_handle_struct
*handle
,
558 const char *path
, const char *name
)
560 SMB_STRUCT_STAT sbuf
;
562 struct db_context
*db
;
565 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
567 if (lp_posix_pathnames()) {
568 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
570 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
577 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
579 return xattr_tdb_removeattr(db
, &id
, name
);
582 static int xattr_tdb_fremovexattr(struct vfs_handle_struct
*handle
,
583 struct files_struct
*fsp
, const char *name
)
585 SMB_STRUCT_STAT sbuf
;
587 struct db_context
*db
;
589 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
591 if (SMB_VFS_FSTAT(fsp
, &sbuf
) == -1) {
595 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
597 return xattr_tdb_removeattr(db
, &id
, name
);
601 * Open the tdb file upon VFS_CONNECT
604 static bool xattr_tdb_init(int snum
, struct db_context
**p_db
)
606 struct db_context
*db
;
610 def_dbname
= state_path("xattr.tdb");
611 if (def_dbname
== NULL
) {
616 dbname
= lp_parm_const_string(snum
, "xattr_tdb", "file", def_dbname
);
618 /* now we know dbname is not NULL */
621 db
= db_open(NULL
, dbname
, 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600);
630 TALLOC_FREE(def_dbname
);
635 TALLOC_FREE(def_dbname
);
640 * On unlink we need to delete the tdb record
642 static int xattr_tdb_unlink(vfs_handle_struct
*handle
, const char *path
)
644 SMB_STRUCT_STAT sbuf
;
646 struct db_context
*db
;
647 struct db_record
*rec
;
650 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
652 if (lp_posix_pathnames()) {
653 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
655 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
662 ret
= SMB_VFS_NEXT_UNLINK(handle
, path
);
668 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
670 rec
= xattr_tdb_lock_attrs(talloc_tos(), db
, &id
);
673 * If rec == NULL there's not much we can do about it
677 rec
->delete_rec(rec
);
685 * On rmdir we need to delete the tdb record
687 static int xattr_tdb_rmdir(vfs_handle_struct
*handle
, const char *path
)
689 SMB_STRUCT_STAT sbuf
;
691 struct db_context
*db
;
692 struct db_record
*rec
;
695 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
, return -1);
697 if (lp_posix_pathnames()) {
698 ret
= SMB_VFS_LSTAT(handle
->conn
, path
, &sbuf
);
700 ret
= SMB_VFS_STAT(handle
->conn
, path
, &sbuf
);
707 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
713 id
= SMB_VFS_FILE_ID_CREATE(handle
->conn
, &sbuf
);
715 rec
= xattr_tdb_lock_attrs(talloc_tos(), db
, &id
);
718 * If rec == NULL there's not much we can do about it
722 rec
->delete_rec(rec
);
730 * Destructor for the VFS private data
733 static void close_xattr_db(void **data
)
735 struct db_context
**p_db
= (struct db_context
**)data
;
739 static int xattr_tdb_connect(vfs_handle_struct
*handle
, const char *service
,
744 struct db_context
*db
;
746 res
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
751 fstrcpy(sname
, service
);
752 snum
= find_service(sname
);
755 * Should not happen, but we should not fail just *here*.
760 if (!xattr_tdb_init(snum
, &db
)) {
761 DEBUG(5, ("Could not init xattr tdb\n"));
762 lp_do_parameter(snum
, "ea support", "False");
766 lp_do_parameter(snum
, "ea support", "True");
768 SMB_VFS_HANDLE_SET_DATA(handle
, db
, close_xattr_db
,
769 struct db_context
, return -1);
774 /* VFS operations structure */
776 static const vfs_op_tuple xattr_tdb_ops
[] = {
777 {SMB_VFS_OP(xattr_tdb_getxattr
), SMB_VFS_OP_GETXATTR
,
778 SMB_VFS_LAYER_TRANSPARENT
},
779 {SMB_VFS_OP(xattr_tdb_fgetxattr
), SMB_VFS_OP_FGETXATTR
,
780 SMB_VFS_LAYER_TRANSPARENT
},
781 {SMB_VFS_OP(xattr_tdb_setxattr
), SMB_VFS_OP_SETXATTR
,
782 SMB_VFS_LAYER_TRANSPARENT
},
783 {SMB_VFS_OP(xattr_tdb_fsetxattr
), SMB_VFS_OP_FSETXATTR
,
784 SMB_VFS_LAYER_TRANSPARENT
},
785 {SMB_VFS_OP(xattr_tdb_listxattr
), SMB_VFS_OP_LISTXATTR
,
786 SMB_VFS_LAYER_TRANSPARENT
},
787 {SMB_VFS_OP(xattr_tdb_flistxattr
), SMB_VFS_OP_FLISTXATTR
,
788 SMB_VFS_LAYER_TRANSPARENT
},
789 {SMB_VFS_OP(xattr_tdb_removexattr
), SMB_VFS_OP_REMOVEXATTR
,
790 SMB_VFS_LAYER_TRANSPARENT
},
791 {SMB_VFS_OP(xattr_tdb_fremovexattr
), SMB_VFS_OP_FREMOVEXATTR
,
792 SMB_VFS_LAYER_TRANSPARENT
},
793 {SMB_VFS_OP(xattr_tdb_unlink
), SMB_VFS_OP_UNLINK
,
794 SMB_VFS_LAYER_TRANSPARENT
},
795 {SMB_VFS_OP(xattr_tdb_rmdir
), SMB_VFS_OP_RMDIR
,
796 SMB_VFS_LAYER_TRANSPARENT
},
797 {SMB_VFS_OP(xattr_tdb_connect
), SMB_VFS_OP_CONNECT
,
798 SMB_VFS_LAYER_TRANSPARENT
},
799 {SMB_VFS_OP(NULL
), SMB_VFS_OP_NOOP
, SMB_VFS_LAYER_NOOP
}
802 NTSTATUS
vfs_xattr_tdb_init(void);
803 NTSTATUS
vfs_xattr_tdb_init(void)
805 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "xattr_tdb",