source: branches/samba-3.2.x/source/modules/vfs_xattr_tdb.c

Last change on this file was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

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