source: trunk/server/source3/modules/vfs_xattr_tdb.c@ 596

Last change on this file since 596 was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

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