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