s3-talloc Change TALLOC_ZERO_P() to talloc_zero()
[nivanova/samba-autobuild/.git] / source3 / modules / vfs_xattr_tdb.c
1 /*
2  * Store posix-level xattrs in a tdb
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "librpc/gen_ndr/xattr.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "../librpc/gen_ndr/ndr_netlogon.h"
26 #include "dbwrap.h"
27 #include "util_tdb.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_VFS
31
32 /*
33  * unmarshall tdb_xattrs
34  */
35
36 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
37                                      const TDB_DATA *data,
38                                      struct tdb_xattrs **presult)
39 {
40         DATA_BLOB blob;
41         enum ndr_err_code ndr_err;
42         struct tdb_xattrs *result;
43
44         if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
45                 return NT_STATUS_NO_MEMORY;
46         }
47
48         if (data->dsize == 0) {
49                 *presult = result;
50                 return NT_STATUS_OK;
51         }
52
53         blob = data_blob_const(data->dptr, data->dsize);
54
55         ndr_err = ndr_pull_struct_blob(&blob, result, result,
56                 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
57
58         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
59                 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
60                           ndr_errstr(ndr_err)));
61                 TALLOC_FREE(result);
62                 return ndr_map_error2ntstatus(ndr_err);
63         }
64
65         *presult = result;
66         return NT_STATUS_OK;
67 }
68
69 /*
70  * marshall tdb_xattrs
71  */
72
73 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
74                                      const struct tdb_xattrs *attribs,
75                                      TDB_DATA *data)
76 {
77         DATA_BLOB blob;
78         enum ndr_err_code ndr_err;
79
80         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
81                 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
82
83         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84                 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
85                           ndr_errstr(ndr_err)));
86                 return ndr_map_error2ntstatus(ndr_err);
87         }
88
89         *data = make_tdb_data(blob.data, blob.length);
90         return NT_STATUS_OK;
91 }
92
93 /*
94  * Load tdb_xattrs for a file from the tdb
95  */
96
97 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
98                                      struct db_context *db_ctx,
99                                      const struct file_id *id,
100                                      struct tdb_xattrs **presult)
101 {
102         uint8 id_buf[16];
103         NTSTATUS status;
104         TDB_DATA data;
105
106         /* For backwards compatibility only store the dev/inode. */
107         push_file_id_16((char *)id_buf, id);
108
109         if (db_ctx->fetch(db_ctx, mem_ctx,
110                           make_tdb_data(id_buf, sizeof(id_buf)),
111                           &data) == -1) {
112                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
113         }
114
115         status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
116         TALLOC_FREE(data.dptr);
117         return status;
118 }
119
120 /*
121  * fetch_lock the tdb_ea record for a file
122  */
123
124 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
125                                               struct db_context *db_ctx,
126                                               const struct file_id *id)
127 {
128         uint8 id_buf[16];
129
130         /* For backwards compatibility only store the dev/inode. */
131         push_file_id_16((char *)id_buf, id);
132         return db_ctx->fetch_locked(db_ctx, mem_ctx,
133                                     make_tdb_data(id_buf, sizeof(id_buf)));
134 }
135
136 /*
137  * Save tdb_xattrs to a previously fetch_locked record
138  */
139
140 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
141                                      const struct tdb_xattrs *attribs)
142 {
143         TDB_DATA data = tdb_null;
144         NTSTATUS status;
145
146         status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
147
148         if (!NT_STATUS_IS_OK(status)) {
149                 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
150                           nt_errstr(status)));
151                 return status;
152         }
153
154         status = rec->store(rec, data, 0);
155
156         TALLOC_FREE(data.dptr);
157
158         return status;
159 }
160
161 /*
162  * Worker routine for getxattr and fgetxattr
163  */
164
165 static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
166                                  const struct file_id *id,
167                                  const char *name, void *value, size_t size)
168 {
169         struct tdb_xattrs *attribs;
170         uint32_t i;
171         ssize_t result = -1;
172         NTSTATUS status;
173
174         DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
175                    file_id_string_tos(id), name));
176
177         status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
178
179         if (!NT_STATUS_IS_OK(status)) {
180                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
181                            nt_errstr(status)));
182                 errno = EINVAL;
183                 return -1;
184         }
185
186         for (i=0; i<attribs->num_eas; i++) {
187                 if (strcmp(attribs->eas[i].name, name) == 0) {
188                         break;
189                 }
190         }
191
192         if (i == attribs->num_eas) {
193                 errno = ENOATTR;
194                 goto fail;
195         }
196
197         if (attribs->eas[i].value.length > size) {
198                 errno = ERANGE;
199                 goto fail;
200         }
201
202         memcpy(value, attribs->eas[i].value.data,
203                attribs->eas[i].value.length);
204         result = attribs->eas[i].value.length;
205
206  fail:
207         TALLOC_FREE(attribs);
208         return result;
209 }
210
211 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
212                                   const char *path, const char *name,
213                                   void *value, size_t size)
214 {
215         SMB_STRUCT_STAT sbuf;
216         struct file_id id;
217         struct db_context *db;
218
219         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
220
221         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
222                 return -1;
223         }
224
225         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
226
227         return xattr_tdb_getattr(db, &id, name, value, size);
228 }
229
230 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
231                                    struct files_struct *fsp,
232                                    const char *name, void *value, size_t size)
233 {
234         SMB_STRUCT_STAT sbuf;
235         struct file_id id;
236         struct db_context *db;
237
238         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
239
240         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
241                 return -1;
242         }
243
244         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
245
246         return xattr_tdb_getattr(db, &id, name, value, size);
247 }
248
249 /*
250  * Worker routine for setxattr and fsetxattr
251  */
252
253 static int xattr_tdb_setattr(struct db_context *db_ctx,
254                              const struct file_id *id, const char *name,
255                              const void *value, size_t size, int flags)
256 {
257         NTSTATUS status;
258         struct db_record *rec;
259         struct tdb_xattrs *attribs;
260         uint32_t i;
261
262         DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
263                    file_id_string_tos(id), name));
264
265         rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
266
267         if (rec == NULL) {
268                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
269                 errno = EINVAL;
270                 return -1;
271         }
272
273         status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
274
275         if (!NT_STATUS_IS_OK(status)) {
276                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
277                            nt_errstr(status)));
278                 TALLOC_FREE(rec);
279                 return -1;
280         }
281
282         for (i=0; i<attribs->num_eas; i++) {
283                 if (strcmp(attribs->eas[i].name, name) == 0) {
284                         if (flags & XATTR_CREATE) {
285                                 TALLOC_FREE(rec);
286                                 errno = EEXIST;
287                                 return -1;
288                         }
289                         break;
290                 }
291         }
292
293         if (i == attribs->num_eas) {
294                 struct xattr_EA *tmp;
295
296                 if (flags & XATTR_REPLACE) {
297                         TALLOC_FREE(rec);
298                         errno = ENOATTR;
299                         return -1;
300                 }
301
302                 tmp = talloc_realloc(
303                         attribs, attribs->eas, struct xattr_EA,
304                         attribs->num_eas+ 1);
305
306                 if (tmp == NULL) {
307                         DEBUG(0, ("talloc_realloc failed\n"));
308                         TALLOC_FREE(rec);
309                         errno = ENOMEM;
310                         return -1;
311                 }
312
313                 attribs->eas = tmp;
314                 attribs->num_eas += 1;
315         }
316
317         attribs->eas[i].name = name;
318         attribs->eas[i].value.data = discard_const_p(uint8, value);
319         attribs->eas[i].value.length = size;
320
321         status = xattr_tdb_save_attrs(rec, attribs);
322
323         TALLOC_FREE(rec);
324
325         if (!NT_STATUS_IS_OK(status)) {
326                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
327                 return -1;
328         }
329
330         return 0;
331 }
332
333 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
334                               const char *path, const char *name,
335                               const void *value, size_t size, int flags)
336 {
337         SMB_STRUCT_STAT sbuf;
338         struct file_id id;
339         struct db_context *db;
340
341         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
342
343         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
344                 return -1;
345         }
346
347         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
348
349         return xattr_tdb_setattr(db, &id, name, value, size, flags);
350 }
351
352 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
353                                struct files_struct *fsp,
354                                const char *name, const void *value,
355                                size_t size, int flags)
356 {
357         SMB_STRUCT_STAT sbuf;
358         struct file_id id;
359         struct db_context *db;
360
361         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
362
363         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
364                 return -1;
365         }
366
367         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
368
369         return xattr_tdb_setattr(db, &id, name, value, size, flags);
370 }
371
372 /*
373  * Worker routine for listxattr and flistxattr
374  */
375
376 static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
377                                   const struct file_id *id, char *list,
378                                   size_t size)
379 {
380         NTSTATUS status;
381         struct tdb_xattrs *attribs;
382         uint32_t i;
383         size_t len = 0;
384
385         status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
386
387         if (!NT_STATUS_IS_OK(status)) {
388                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
389                            nt_errstr(status)));
390                 errno = EINVAL;
391                 return -1;
392         }
393
394         DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
395                    attribs->num_eas));
396
397         for (i=0; i<attribs->num_eas; i++) {
398                 size_t tmp;
399
400                 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
401                            attribs->eas[i].name));
402
403                 tmp = strlen(attribs->eas[i].name);
404
405                 /*
406                  * Try to protect against overflow
407                  */
408
409                 if (len + (tmp+1) < len) {
410                         TALLOC_FREE(attribs);
411                         errno = EINVAL;
412                         return -1;
413                 }
414
415                 /*
416                  * Take care of the terminating NULL
417                  */
418                 len += (tmp + 1);
419         }
420
421         if (len > size) {
422                 TALLOC_FREE(attribs);
423                 errno = ERANGE;
424                 return -1;
425         }
426
427         len = 0;
428
429         for (i=0; i<attribs->num_eas; i++) {
430                 strlcpy(list+len, attribs->eas[i].name,
431                         size-len);
432                 len += (strlen(attribs->eas[i].name) + 1);
433         }
434
435         TALLOC_FREE(attribs);
436         return len;
437 }
438
439 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
440                                    const char *path, char *list, size_t size)
441 {
442         SMB_STRUCT_STAT sbuf;
443         struct file_id id;
444         struct db_context *db;
445
446         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
447
448         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
449                 return -1;
450         }
451
452         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
453
454         return xattr_tdb_listattr(db, &id, list, size);
455 }
456
457 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
458                                     struct files_struct *fsp, char *list,
459                                     size_t size)
460 {
461         SMB_STRUCT_STAT sbuf;
462         struct file_id id;
463         struct db_context *db;
464
465         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
466
467         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
468                 return -1;
469         }
470
471         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
472
473         return xattr_tdb_listattr(db, &id, list, size);
474 }
475
476 /*
477  * Worker routine for removexattr and fremovexattr
478  */
479
480 static int xattr_tdb_removeattr(struct db_context *db_ctx,
481                                 const struct file_id *id, const char *name)
482 {
483         NTSTATUS status;
484         struct db_record *rec;
485         struct tdb_xattrs *attribs;
486         uint32_t i;
487
488         rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
489
490         if (rec == NULL) {
491                 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
492                 errno = EINVAL;
493                 return -1;
494         }
495
496         status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
497
498         if (!NT_STATUS_IS_OK(status)) {
499                 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
500                            nt_errstr(status)));
501                 TALLOC_FREE(rec);
502                 return -1;
503         }
504
505         for (i=0; i<attribs->num_eas; i++) {
506                 if (strcmp(attribs->eas[i].name, name) == 0) {
507                         break;
508                 }
509         }
510
511         if (i == attribs->num_eas) {
512                 TALLOC_FREE(rec);
513                 errno = ENOATTR;
514                 return -1;
515         }
516
517         attribs->eas[i] =
518                 attribs->eas[attribs->num_eas-1];
519         attribs->num_eas -= 1;
520
521         if (attribs->num_eas == 0) {
522                 rec->delete_rec(rec);
523                 TALLOC_FREE(rec);
524                 return 0;
525         }
526
527         status = xattr_tdb_save_attrs(rec, attribs);
528
529         TALLOC_FREE(rec);
530
531         if (!NT_STATUS_IS_OK(status)) {
532                 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
533                 return -1;
534         }
535
536         return 0;
537 }
538
539 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
540                                  const char *path, const char *name)
541 {
542         SMB_STRUCT_STAT sbuf;
543         struct file_id id;
544         struct db_context *db;
545
546         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
547
548         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
549                 return -1;
550         }
551
552         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
553
554         return xattr_tdb_removeattr(db, &id, name);
555 }
556
557 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
558                                   struct files_struct *fsp, const char *name)
559 {
560         SMB_STRUCT_STAT sbuf;
561         struct file_id id;
562         struct db_context *db;
563
564         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
565
566         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
567                 return -1;
568         }
569
570         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
571
572         return xattr_tdb_removeattr(db, &id, name);
573 }
574
575 /*
576  * Open the tdb file upon VFS_CONNECT
577  */
578
579 static bool xattr_tdb_init(int snum, struct db_context **p_db)
580 {
581         struct db_context *db;
582         const char *dbname;
583         char *def_dbname;
584
585         def_dbname = state_path("xattr.tdb");
586         if (def_dbname == NULL) {
587                 errno = ENOSYS;
588                 return false;
589         }
590
591         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
592
593         /* now we know dbname is not NULL */
594
595         become_root();
596         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
597         unbecome_root();
598
599         if (db == NULL) {
600 #if defined(ENOTSUP)
601                 errno = ENOTSUP;
602 #else
603                 errno = ENOSYS;
604 #endif
605                 TALLOC_FREE(def_dbname);
606                 return false;
607         }
608
609         *p_db = db;
610         TALLOC_FREE(def_dbname);
611         return true;
612 }
613
614 /*
615  * On unlink we need to delete the tdb record
616  */
617 static int xattr_tdb_unlink(vfs_handle_struct *handle,
618                             const struct smb_filename *smb_fname)
619 {
620         struct smb_filename *smb_fname_tmp = NULL;
621         struct file_id id;
622         struct db_context *db;
623         struct db_record *rec;
624         NTSTATUS status;
625         int ret = -1;
626         bool remove_record = false;
627
628         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
629
630         status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
631         if (!NT_STATUS_IS_OK(status)) {
632                 errno = map_errno_from_nt_status(status);
633                 return -1;
634         }
635
636         if (lp_posix_pathnames()) {
637                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
638         } else {
639                 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
640         }
641         if (ret == -1) {
642                 goto out;
643         }
644
645         if (smb_fname_tmp->st.st_ex_nlink == 1) {
646                 /* Only remove record on last link to file. */
647                 remove_record = true;
648         }
649
650         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
651
652         if (ret == -1) {
653                 goto out;
654         }
655
656         if (!remove_record) {
657                 goto out;
658         }
659
660         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
661
662         rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
663
664         /*
665          * If rec == NULL there's not much we can do about it
666          */
667
668         if (rec != NULL) {
669                 rec->delete_rec(rec);
670                 TALLOC_FREE(rec);
671         }
672
673  out:
674         TALLOC_FREE(smb_fname_tmp);
675         return ret;
676 }
677
678 /*
679  * On rmdir we need to delete the tdb record
680  */
681 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
682 {
683         SMB_STRUCT_STAT sbuf;
684         struct file_id id;
685         struct db_context *db;
686         struct db_record *rec;
687         int ret;
688
689         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
690
691         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
692                 return -1;
693         }
694
695         ret = SMB_VFS_NEXT_RMDIR(handle, path);
696
697         if (ret == -1) {
698                 return -1;
699         }
700
701         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
702
703         rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
704
705         /*
706          * If rec == NULL there's not much we can do about it
707          */
708
709         if (rec != NULL) {
710                 rec->delete_rec(rec);
711                 TALLOC_FREE(rec);
712         }
713
714         return 0;
715 }
716
717 /*
718  * Destructor for the VFS private data
719  */
720
721 static void close_xattr_db(void **data)
722 {
723         struct db_context **p_db = (struct db_context **)data;
724         TALLOC_FREE(*p_db);
725 }
726
727 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
728                           const char *user)
729 {
730         char *sname = NULL;
731         int res, snum;
732         struct db_context *db;
733
734         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
735         if (res < 0) {
736                 return res;
737         }
738
739         snum = find_service(talloc_tos(), service, &sname);
740         if (snum == -1 || sname == NULL) {
741                 /*
742                  * Should not happen, but we should not fail just *here*.
743                  */
744                 return 0;
745         }
746
747         if (!xattr_tdb_init(snum, &db)) {
748                 DEBUG(5, ("Could not init xattr tdb\n"));
749                 lp_do_parameter(snum, "ea support", "False");
750                 return 0;
751         }
752
753         lp_do_parameter(snum, "ea support", "True");
754
755         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
756                                 struct db_context, return -1);
757
758         return 0;
759 }
760
761 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
762         .getxattr = xattr_tdb_getxattr,
763         .fgetxattr = xattr_tdb_fgetxattr,
764         .setxattr = xattr_tdb_setxattr,
765         .fsetxattr = xattr_tdb_fsetxattr,
766         .listxattr = xattr_tdb_listxattr,
767         .flistxattr = xattr_tdb_flistxattr,
768         .removexattr = xattr_tdb_removexattr,
769         .fremovexattr = xattr_tdb_fremovexattr,
770         .unlink = xattr_tdb_unlink,
771         .rmdir = xattr_tdb_rmdir,
772         .connect_fn = xattr_tdb_connect,
773 };
774
775 NTSTATUS vfs_xattr_tdb_init(void);
776 NTSTATUS vfs_xattr_tdb_init(void)
777 {
778         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
779                                 &vfs_xattr_tdb_fns);
780 }