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",