32968ae083fa5de53284cbb2f2f0bc201d873b00
[kamenim/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  * Copyright (C) Andrew Bartlett, 2012
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include "includes.h"
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"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_VFS
31
32 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db);
33
34 static int xattr_tdb_get_file_id(struct vfs_handle_struct *handle,
35                                 const char *path, struct file_id *id)
36 {
37         int ret;
38         TALLOC_CTX *frame = talloc_stackframe();
39         struct smb_filename *smb_fname;
40
41         smb_fname = synthetic_smb_fname(frame, path, NULL, NULL, 0);
42         if (smb_fname == NULL) {
43                 TALLOC_FREE(frame);
44                 errno = ENOMEM;
45                 return -1;
46         }
47
48         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
49
50         if (ret == -1) {
51                 TALLOC_FREE(frame); 
52                 return -1;
53         }
54
55         *id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname->st);
56         TALLOC_FREE(frame);
57         return 0;
58 }
59
60 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
61                                 const struct smb_filename *smb_fname,
62                                 const char *name,
63                                 void *value,
64                                 size_t size)
65 {
66         struct file_id id;
67         struct db_context *db;
68         ssize_t xattr_size;
69         int ret;
70         DATA_BLOB blob;
71         TALLOC_CTX *frame = talloc_stackframe();
72
73         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
74                                 if (!xattr_tdb_init(-1, frame, &db))
75                                 {
76                                         TALLOC_FREE(frame); return -1;
77                                 });
78
79         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
80         if (ret == -1) {
81                 TALLOC_FREE(frame);
82                 return -1;
83         }
84
85         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
86         if (xattr_size < 0) {
87                 errno = ENOATTR;
88                 TALLOC_FREE(frame);
89                 return -1;
90         }
91
92         if (size == 0) {
93                 TALLOC_FREE(frame);
94                 return xattr_size;
95         }
96
97         if (blob.length > size) {
98                 TALLOC_FREE(frame);
99                 errno = ERANGE;
100                 return -1;
101         }
102         memcpy(value, blob.data, xattr_size);
103         TALLOC_FREE(frame);
104         return xattr_size;
105 }
106
107 struct xattr_tdb_getxattrat_state {
108         struct vfs_aio_state vfs_aio_state;
109         ssize_t xattr_size;
110         uint8_t *xattr_value;
111 };
112
113 static struct tevent_req *xattr_tdb_getxattrat_send(
114                         TALLOC_CTX *mem_ctx,
115                         const struct smb_vfs_ev_glue *evg,
116                         struct vfs_handle_struct *handle,
117                         files_struct *dir_fsp,
118                         const struct smb_filename *smb_fname,
119                         const char *xattr_name,
120                         size_t alloc_hint)
121 {
122         struct tevent_context *ev = smb_vfs_ev_glue_ev_ctx(evg);
123         struct tevent_req *req = NULL;
124         struct xattr_tdb_getxattrat_state *state = NULL;
125         struct smb_filename *cwd = NULL;
126         struct db_context *db = NULL;
127         struct file_id id;
128         int ret;
129         int error;
130         int cwd_ret;
131         DATA_BLOB xattr_blob;
132
133         req = tevent_req_create(mem_ctx, &state,
134                                 struct xattr_tdb_getxattrat_state);
135         if (req == NULL) {
136                 return NULL;
137         }
138         state->xattr_size = -1;
139
140         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
141                                 if (!xattr_tdb_init(-1, state, &db)) {
142                                         tevent_req_error(req, EIO);
143                                         return tevent_req_post(req, ev);
144                                 });
145
146         cwd = SMB_VFS_GETWD(dir_fsp->conn, state);
147         if (tevent_req_nomem(cwd, req)) {
148                 return tevent_req_post(req, ev);
149         }
150
151         ret = SMB_VFS_CHDIR(dir_fsp->conn, dir_fsp->fsp_name);
152         if (ret != 0) {
153                 tevent_req_error(req, errno);
154                 return tevent_req_post(req, ev);
155         }
156
157         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
158         error = errno;
159
160         cwd_ret = SMB_VFS_CHDIR(dir_fsp->conn, cwd);
161         SMB_ASSERT(cwd_ret == 0);
162
163         if (ret == -1) {
164                 tevent_req_error(req, error);
165                 return tevent_req_post(req, ev);
166         }
167
168         state->xattr_size = xattr_tdb_getattr(db,
169                                               state,
170                                               &id,
171                                               xattr_name,
172                                               &xattr_blob);
173         if (state->xattr_size == -1) {
174                 tevent_req_error(req, errno);
175                 return tevent_req_post(req, ev);
176         }
177
178         if (alloc_hint == 0) {
179                 /*
180                  * The caller only wants to know the size.
181                  */
182                 tevent_req_done(req);
183                 return tevent_req_post(req, ev);
184         }
185
186         if (state->xattr_size == 0) {
187                 /*
188                  * There's no data.
189                  */
190                 tevent_req_done(req);
191                 return tevent_req_post(req, ev);
192         }
193
194         if (xattr_blob.length > alloc_hint) {
195                 /*
196                  * The data doesn't fit.
197                  */
198                 state->xattr_size = -1;
199                 tevent_req_error(req, ERANGE);
200                 return tevent_req_post(req, ev);
201         }
202
203         /*
204          * take the whole blob.
205          */
206         state->xattr_value = xattr_blob.data;
207
208         tevent_req_done(req);
209         return tevent_req_post(req, ev);
210 }
211
212 static ssize_t xattr_tdb_getxattrat_recv(struct tevent_req *req,
213                                          struct vfs_aio_state *aio_state,
214                                          TALLOC_CTX *mem_ctx,
215                                          uint8_t **xattr_value)
216 {
217         struct xattr_tdb_getxattrat_state *state = tevent_req_data(
218                 req, struct xattr_tdb_getxattrat_state);
219         ssize_t xattr_size;
220
221         if (tevent_req_is_unix_error(req, &aio_state->error)) {
222                 tevent_req_received(req);
223                 return -1;
224         }
225
226         *aio_state = state->vfs_aio_state;
227         xattr_size = state->xattr_size;
228         if (xattr_value != NULL) {
229                 *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
230         }
231
232         tevent_req_received(req);
233         return xattr_size;
234 }
235
236 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
237                                    struct files_struct *fsp,
238                                    const char *name, void *value, size_t size)
239 {
240         SMB_STRUCT_STAT sbuf;
241         struct file_id id;
242         struct db_context *db;
243         ssize_t xattr_size;
244         DATA_BLOB blob;
245         TALLOC_CTX *frame = talloc_stackframe();
246
247         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
248                                 if (!xattr_tdb_init(-1, frame, &db))
249                                 {
250                                         TALLOC_FREE(frame); return -1;
251                                 });
252
253         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
254                 TALLOC_FREE(frame);
255                 return -1;
256         }
257
258         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
259
260         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
261         if (xattr_size < 0) {
262                 errno = ENOATTR;
263                 TALLOC_FREE(frame);
264                 return -1;
265         }
266
267         if (size == 0) {
268                 TALLOC_FREE(frame);
269                 return xattr_size;
270         }
271
272         if (blob.length > size) {
273                 TALLOC_FREE(frame);
274                 errno = ERANGE;
275                 return -1;
276         }
277         memcpy(value, blob.data, xattr_size);
278         TALLOC_FREE(frame);
279         return xattr_size;
280 }
281
282 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
283                                 const struct smb_filename *smb_fname,
284                                 const char *name,
285                                 const void *value,
286                                 size_t size,
287                                 int flags)
288 {
289         struct file_id id;
290         struct db_context *db;
291         int ret;
292         TALLOC_CTX *frame = talloc_stackframe();
293
294         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
295                                 if (!xattr_tdb_init(-1, frame, &db))
296                                 {
297                                         TALLOC_FREE(frame); return -1;
298                                 });
299
300         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
301         if (ret == -1) {
302                 TALLOC_FREE(frame);
303                 return -1;
304         }
305
306         ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
307         TALLOC_FREE(frame);
308         return ret;
309 }
310
311 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
312                                struct files_struct *fsp,
313                                const char *name, const void *value,
314                                size_t size, int flags)
315 {
316         SMB_STRUCT_STAT sbuf;
317         struct file_id id;
318         struct db_context *db;
319         int ret;
320         TALLOC_CTX *frame = talloc_stackframe();
321
322         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
323                                 if (!xattr_tdb_init(-1, frame, &db))
324                                 {
325                                         TALLOC_FREE(frame); return -1;
326                                 });
327
328         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
329                 TALLOC_FREE(frame);
330                 return -1;
331         }
332
333         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
334
335         ret = xattr_tdb_setattr(db, &id, name, value, size, flags);
336         TALLOC_FREE(frame);
337         return ret;
338
339 }
340
341 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
342                                 const struct smb_filename *smb_fname,
343                                 char *list,
344                                 size_t size)
345 {
346         struct file_id id;
347         struct db_context *db;
348         int ret;
349         TALLOC_CTX *frame = talloc_stackframe();
350
351         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
352                                 if (!xattr_tdb_init(-1, frame, &db))
353                                 {
354                                         TALLOC_FREE(frame); return -1;
355                                 });
356
357         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
358         if (ret == -1) {
359                 TALLOC_FREE(frame);
360                 return -1;
361         }
362
363         ret = xattr_tdb_listattr(db, &id, list, size);
364         TALLOC_FREE(frame);
365         return ret;
366
367 }
368
369 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
370                                     struct files_struct *fsp, char *list,
371                                     size_t size)
372 {
373         SMB_STRUCT_STAT sbuf;
374         struct file_id id;
375         struct db_context *db;
376         int ret;
377         TALLOC_CTX *frame = talloc_stackframe();
378
379         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
380                                 if (!xattr_tdb_init(-1, frame, &db))
381                                 {
382                                         TALLOC_FREE(frame); return -1;
383                                 });
384
385         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
386                 TALLOC_FREE(frame);
387                 return -1;
388         }
389
390         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
391
392         ret = xattr_tdb_listattr(db, &id, list, size);
393         TALLOC_FREE(frame);
394         return ret;
395 }
396
397 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
398                                 const struct smb_filename *smb_fname,
399                                 const char *name)
400 {
401         struct file_id id;
402         struct db_context *db;
403         int ret;
404         TALLOC_CTX *frame = talloc_stackframe();
405
406         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
407                                 if (!xattr_tdb_init(-1, frame, &db))
408                                 {
409                                         TALLOC_FREE(frame); return -1;
410                                 });
411
412         ret = xattr_tdb_get_file_id(handle, smb_fname->base_name, &id);
413         if (ret == -1) {
414                 TALLOC_FREE(frame);
415                 return ret;
416         }
417
418         
419         ret = xattr_tdb_removeattr(db, &id, name);
420         TALLOC_FREE(frame);
421         return ret;
422 }
423
424 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
425                                   struct files_struct *fsp, const char *name)
426 {
427         SMB_STRUCT_STAT sbuf;
428         struct file_id id;
429         struct db_context *db;
430         int ret;
431         TALLOC_CTX *frame = talloc_stackframe();
432
433         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
434                                 if (!xattr_tdb_init(-1, frame, &db))
435                                 {
436                                         TALLOC_FREE(frame); return -1;
437                                 });
438
439         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
440                 TALLOC_FREE(frame);
441                 return -1;
442         }
443
444         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
445
446         ret = xattr_tdb_removeattr(db, &id, name);
447         TALLOC_FREE(frame);
448         return ret;
449 }
450
451 /*
452  * Open the tdb file upon VFS_CONNECT
453  */
454
455 static bool xattr_tdb_init(int snum, TALLOC_CTX *mem_ctx, struct db_context **p_db)
456 {
457         struct db_context *db;
458         const char *dbname;
459         char *def_dbname;
460
461         def_dbname = state_path(talloc_tos(), "xattr.tdb");
462         if (def_dbname == NULL) {
463                 errno = ENOSYS;
464                 return false;
465         }
466
467         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
468
469         /* now we know dbname is not NULL */
470
471         become_root();
472         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
473                      DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
474         unbecome_root();
475
476         if (db == NULL) {
477 #if defined(ENOTSUP)
478                 errno = ENOTSUP;
479 #else
480                 errno = ENOSYS;
481 #endif
482                 TALLOC_FREE(def_dbname);
483                 return false;
484         }
485
486         *p_db = db;
487         TALLOC_FREE(def_dbname);
488         return true;
489 }
490
491 static int xattr_tdb_open(vfs_handle_struct *handle,
492                         struct smb_filename *smb_fname,
493                         files_struct *fsp,
494                         int flags,
495                         mode_t mode)
496 {
497         struct db_context *db = NULL;
498         TALLOC_CTX *frame = NULL;
499         int ret;
500
501         fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle,
502                                 smb_fname, fsp,
503                                 flags,
504                                 mode);
505
506         if (fsp->fh->fd < 0) {
507                 return fsp->fh->fd;
508         }
509
510         if ((flags & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)) {
511                 return fsp->fh->fd;
512         }
513
514         /*
515          * We know we used O_CREAT|O_EXCL and it worked.
516          * We must have created the file.
517          */
518
519         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
520         if (ret == -1) {
521                 /* Can't happen... */
522                 DBG_WARNING("SMB_VFS_FSTAT failed on file %s (%s)\n",
523                         smb_fname_str_dbg(smb_fname),
524                         strerror(errno));
525                 return -1;
526         }
527         fsp->file_id = SMB_VFS_FILE_ID_CREATE(fsp->conn, &smb_fname->st);
528
529         frame = talloc_stackframe();
530         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
531                                 if (!xattr_tdb_init(-1, frame, &db))
532                                 {
533                                         TALLOC_FREE(frame); return -1;
534                                 });
535
536         xattr_tdb_remove_all_attrs(db, &fsp->file_id);
537         TALLOC_FREE(frame);
538         return fsp->fh->fd;
539 }
540
541 static int xattr_tdb_mkdir(vfs_handle_struct *handle,
542                 const struct smb_filename *smb_fname,
543                 mode_t mode)
544 {
545         struct db_context *db = NULL;
546         TALLOC_CTX *frame = NULL;
547         struct file_id fileid;
548         int ret;
549         struct smb_filename *smb_fname_tmp = NULL;
550
551         ret = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
552         if (ret < 0) {
553                 return ret;
554         }
555
556         frame = talloc_stackframe();
557         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
558         if (smb_fname_tmp == NULL) {
559                 TALLOC_FREE(frame);
560                 errno = ENOMEM;
561                 return -1;
562         }
563
564         /* Always use LSTAT here - we just creaded the directory. */
565         ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
566         if (ret == -1) {
567                 /* Rename race. Let upper level take care of it. */
568                 TALLOC_FREE(frame);
569                 return -1;
570         }
571         if (!S_ISDIR(smb_fname_tmp->st.st_ex_mode)) {
572                 /* Rename race. Let upper level take care of it. */
573                 TALLOC_FREE(frame);
574                 return -1;
575         }
576
577         fileid = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
578
579         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
580                                 if (!xattr_tdb_init(-1, frame, &db))
581                                 {
582                                         TALLOC_FREE(frame); return -1;
583                                 });
584
585         xattr_tdb_remove_all_attrs(db, &fileid);
586         TALLOC_FREE(frame);
587         return 0;
588 }
589
590 /*
591  * On unlink we need to delete the tdb record
592  */
593 static int xattr_tdb_unlink(vfs_handle_struct *handle,
594                             const struct smb_filename *smb_fname)
595 {
596         struct smb_filename *smb_fname_tmp = NULL;
597         struct file_id id;
598         struct db_context *db;
599         int ret = -1;
600         bool remove_record = false;
601         TALLOC_CTX *frame = talloc_stackframe();
602
603         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
604                                 if (!xattr_tdb_init(-1, frame, &db))
605                                 {
606                                         TALLOC_FREE(frame); return -1;
607                                 });
608
609         smb_fname_tmp = cp_smb_filename(frame, smb_fname);
610         if (smb_fname_tmp == NULL) {
611                 TALLOC_FREE(frame);
612                 errno = ENOMEM;
613                 return -1;
614         }
615
616         if (smb_fname_tmp->flags & SMB_FILENAME_POSIX_PATH) {
617                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
618         } else {
619                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
620         }
621         if (ret == -1) {
622                 goto out;
623         }
624
625         if (smb_fname_tmp->st.st_ex_nlink == 1) {
626                 /* Only remove record on last link to file. */
627                 remove_record = true;
628         }
629
630         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
631
632         if (ret == -1) {
633                 goto out;
634         }
635
636         if (!remove_record) {
637                 goto out;
638         }
639
640         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st);
641
642         xattr_tdb_remove_all_attrs(db, &id);
643
644  out:
645         TALLOC_FREE(frame);
646         return ret;
647 }
648
649 /*
650  * On rmdir we need to delete the tdb record
651  */
652 static int xattr_tdb_rmdir(vfs_handle_struct *handle,
653                         const struct smb_filename *smb_fname)
654 {
655         SMB_STRUCT_STAT sbuf;
656         struct file_id id;
657         struct db_context *db;
658         int ret;
659         TALLOC_CTX *frame = talloc_stackframe();
660
661         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
662                                 if (!xattr_tdb_init(-1, frame, &db))
663                                 {
664                                         TALLOC_FREE(frame); return -1;
665                                 });
666
667         if (vfs_stat_smb_basename(handle->conn,
668                                 smb_fname,
669                                 &sbuf) == -1) {
670                 TALLOC_FREE(frame);
671                 return -1;
672         }
673
674         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
675
676         if (ret == -1) {
677                 TALLOC_FREE(frame);
678                 return -1;
679         }
680
681         id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &sbuf);
682
683         xattr_tdb_remove_all_attrs(db, &id);
684
685         TALLOC_FREE(frame);
686         return 0;
687 }
688
689 /*
690  * Destructor for the VFS private data
691  */
692
693 static void close_xattr_db(void **data)
694 {
695         struct db_context **p_db = (struct db_context **)data;
696         TALLOC_FREE(*p_db);
697 }
698
699 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
700                           const char *user)
701 {
702         char *sname = NULL;
703         int res, snum;
704         struct db_context *db;
705
706         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
707         if (res < 0) {
708                 return res;
709         }
710
711         snum = find_service(talloc_tos(), service, &sname);
712         if (snum == -1 || sname == NULL) {
713                 /*
714                  * Should not happen, but we should not fail just *here*.
715                  */
716                 return 0;
717         }
718
719         if (!xattr_tdb_init(snum, NULL, &db)) {
720                 DEBUG(5, ("Could not init xattr tdb\n"));
721                 lp_do_parameter(snum, "ea support", "False");
722                 return 0;
723         }
724
725         lp_do_parameter(snum, "ea support", "True");
726
727         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
728                                 struct db_context, return -1);
729
730         return 0;
731 }
732
733 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
734         .getxattr_fn = xattr_tdb_getxattr,
735         .getxattrat_send_fn = xattr_tdb_getxattrat_send,
736         .getxattrat_recv_fn = xattr_tdb_getxattrat_recv,
737         .fgetxattr_fn = xattr_tdb_fgetxattr,
738         .setxattr_fn = xattr_tdb_setxattr,
739         .fsetxattr_fn = xattr_tdb_fsetxattr,
740         .listxattr_fn = xattr_tdb_listxattr,
741         .flistxattr_fn = xattr_tdb_flistxattr,
742         .removexattr_fn = xattr_tdb_removexattr,
743         .fremovexattr_fn = xattr_tdb_fremovexattr,
744         .open_fn = xattr_tdb_open,
745         .mkdir_fn = xattr_tdb_mkdir,
746         .unlink_fn = xattr_tdb_unlink,
747         .rmdir_fn = xattr_tdb_rmdir,
748         .connect_fn = xattr_tdb_connect,
749 };
750
751 static_decl_vfs;
752 NTSTATUS vfs_xattr_tdb_init(TALLOC_CTX *ctx)
753 {
754         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
755                                 &vfs_xattr_tdb_fns);
756 }