s3: Remove smbd_messaging_context() from reply_writeunlock()
[Samba/gebeck_regimport.git] / source3 / modules / vfs_xattr_tdb.c
blobb11e7eea28c7fa2949eb165dd76ca4655b4e87bd
1 /*
2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Volker Lendecke, 2007
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.
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.
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/>.
20 #include "includes.h"
21 #include "librpc/gen_ndr/xattr.h"
22 #include "librpc/gen_ndr/ndr_xattr.h"
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_VFS
28 * unmarshall tdb_xattrs
31 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
32 const TDB_DATA *data,
33 struct tdb_xattrs **presult)
35 DATA_BLOB blob;
36 enum ndr_err_code ndr_err;
37 struct tdb_xattrs *result;
39 if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) {
40 return NT_STATUS_NO_MEMORY;
43 if (data->dsize == 0) {
44 *presult = result;
45 return NT_STATUS_OK;
48 blob = data_blob_const(data->dptr, data->dsize);
50 ndr_err = ndr_pull_struct_blob(&blob, result, result,
51 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
53 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
54 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
55 ndr_errstr(ndr_err)));
56 TALLOC_FREE(result);
57 return ndr_map_error2ntstatus(ndr_err);;
60 *presult = result;
61 return NT_STATUS_OK;
65 * marshall tdb_xattrs
68 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
69 const struct tdb_xattrs *attribs,
70 TDB_DATA *data)
72 DATA_BLOB blob;
73 enum ndr_err_code ndr_err;
75 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
76 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
78 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
79 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
80 ndr_errstr(ndr_err)));
81 return ndr_map_error2ntstatus(ndr_err);;
84 *data = make_tdb_data(blob.data, blob.length);
85 return NT_STATUS_OK;
89 * Load tdb_xattrs for a file from the tdb
92 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
93 struct db_context *db_ctx,
94 const struct file_id *id,
95 struct tdb_xattrs **presult)
97 uint8 id_buf[16];
98 NTSTATUS status;
99 TDB_DATA data;
101 /* For backwards compatibility only store the dev/inode. */
102 push_file_id_16((char *)id_buf, id);
104 if (db_ctx->fetch(db_ctx, mem_ctx,
105 make_tdb_data(id_buf, sizeof(id_buf)),
106 &data) == -1) {
107 return NT_STATUS_INTERNAL_DB_CORRUPTION;
110 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
111 TALLOC_FREE(data.dptr);
112 return status;
116 * fetch_lock the tdb_ea record for a file
119 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
120 struct db_context *db_ctx,
121 const struct file_id *id)
123 uint8 id_buf[16];
125 /* For backwards compatibility only store the dev/inode. */
126 push_file_id_16((char *)id_buf, id);
127 return db_ctx->fetch_locked(db_ctx, mem_ctx,
128 make_tdb_data(id_buf, sizeof(id_buf)));
132 * Save tdb_xattrs to a previously fetch_locked record
135 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
136 const struct tdb_xattrs *attribs)
138 TDB_DATA data = tdb_null;
139 NTSTATUS status;
141 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
143 if (!NT_STATUS_IS_OK(status)) {
144 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
145 nt_errstr(status)));
146 return status;
149 status = rec->store(rec, data, 0);
151 TALLOC_FREE(data.dptr);
153 return status;
157 * Worker routine for getxattr and fgetxattr
160 static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
161 const struct file_id *id,
162 const char *name, void *value, size_t size)
164 struct tdb_xattrs *attribs;
165 uint32_t i;
166 ssize_t result = -1;
167 NTSTATUS status;
169 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
170 file_id_string_tos(id), name));
172 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
174 if (!NT_STATUS_IS_OK(status)) {
175 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
176 nt_errstr(status)));
177 errno = EINVAL;
178 return -1;
181 for (i=0; i<attribs->num_eas; i++) {
182 if (strcmp(attribs->eas[i].name, name) == 0) {
183 break;
187 if (i == attribs->num_eas) {
188 errno = ENOATTR;
189 goto fail;
192 if (attribs->eas[i].value.length > size) {
193 errno = ERANGE;
194 goto fail;
197 memcpy(value, attribs->eas[i].value.data,
198 attribs->eas[i].value.length);
199 result = attribs->eas[i].value.length;
201 fail:
202 TALLOC_FREE(attribs);
203 return result;
206 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
207 const char *path, const char *name,
208 void *value, size_t size)
210 SMB_STRUCT_STAT sbuf;
211 struct file_id id;
212 struct db_context *db;
214 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
216 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
217 return -1;
220 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
222 return xattr_tdb_getattr(db, &id, name, value, size);
225 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
226 struct files_struct *fsp,
227 const char *name, void *value, size_t size)
229 SMB_STRUCT_STAT sbuf;
230 struct file_id id;
231 struct db_context *db;
233 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
235 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
236 return -1;
239 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
241 return xattr_tdb_getattr(db, &id, name, value, size);
245 * Worker routine for setxattr and fsetxattr
248 static int xattr_tdb_setattr(struct db_context *db_ctx,
249 const struct file_id *id, const char *name,
250 const void *value, size_t size, int flags)
252 NTSTATUS status;
253 struct db_record *rec;
254 struct tdb_xattrs *attribs;
255 uint32_t i;
257 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
258 file_id_string_tos(id), name));
260 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
262 if (rec == NULL) {
263 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
264 errno = EINVAL;
265 return -1;
268 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
270 if (!NT_STATUS_IS_OK(status)) {
271 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
272 nt_errstr(status)));
273 TALLOC_FREE(rec);
274 return -1;
277 for (i=0; i<attribs->num_eas; i++) {
278 if (strcmp(attribs->eas[i].name, name) == 0) {
279 if (flags & XATTR_CREATE) {
280 TALLOC_FREE(rec);
281 errno = EEXIST;
282 return -1;
284 break;
288 if (i == attribs->num_eas) {
289 struct xattr_EA *tmp;
291 if (flags & XATTR_REPLACE) {
292 TALLOC_FREE(rec);
293 errno = ENOATTR;
294 return -1;
297 tmp = TALLOC_REALLOC_ARRAY(
298 attribs, attribs->eas, struct xattr_EA,
299 attribs->num_eas+ 1);
301 if (tmp == NULL) {
302 DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
303 TALLOC_FREE(rec);
304 errno = ENOMEM;
305 return -1;
308 attribs->eas = tmp;
309 attribs->num_eas += 1;
312 attribs->eas[i].name = name;
313 attribs->eas[i].value.data = CONST_DISCARD(uint8 *, value);
314 attribs->eas[i].value.length = size;
316 status = xattr_tdb_save_attrs(rec, attribs);
318 TALLOC_FREE(rec);
320 if (!NT_STATUS_IS_OK(status)) {
321 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
322 return -1;
325 return 0;
328 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
329 const char *path, const char *name,
330 const void *value, size_t size, int flags)
332 SMB_STRUCT_STAT sbuf;
333 struct file_id id;
334 struct db_context *db;
336 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
338 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
339 return -1;
342 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
344 return xattr_tdb_setattr(db, &id, name, value, size, flags);
347 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
348 struct files_struct *fsp,
349 const char *name, const void *value,
350 size_t size, int flags)
352 SMB_STRUCT_STAT sbuf;
353 struct file_id id;
354 struct db_context *db;
356 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
358 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
359 return -1;
362 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
364 return xattr_tdb_setattr(db, &id, name, value, size, flags);
368 * Worker routine for listxattr and flistxattr
371 static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
372 const struct file_id *id, char *list,
373 size_t size)
375 NTSTATUS status;
376 struct tdb_xattrs *attribs;
377 uint32_t i;
378 size_t len = 0;
380 status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
382 if (!NT_STATUS_IS_OK(status)) {
383 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
384 nt_errstr(status)));
385 errno = EINVAL;
386 return -1;
389 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
390 attribs->num_eas));
392 for (i=0; i<attribs->num_eas; i++) {
393 size_t tmp;
395 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
396 attribs->eas[i].name));
398 tmp = strlen(attribs->eas[i].name);
401 * Try to protect against overflow
404 if (len + (tmp+1) < len) {
405 TALLOC_FREE(attribs);
406 errno = EINVAL;
407 return -1;
411 * Take care of the terminating NULL
413 len += (tmp + 1);
416 if (len > size) {
417 TALLOC_FREE(attribs);
418 errno = ERANGE;
419 return -1;
422 len = 0;
424 for (i=0; i<attribs->num_eas; i++) {
425 strlcpy(list+len, attribs->eas[i].name,
426 size-len);
427 len += (strlen(attribs->eas[i].name) + 1);
430 TALLOC_FREE(attribs);
431 return len;
434 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
435 const char *path, char *list, size_t size)
437 SMB_STRUCT_STAT sbuf;
438 struct file_id id;
439 struct db_context *db;
441 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
443 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
444 return -1;
447 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
449 return xattr_tdb_listattr(db, &id, list, size);
452 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
453 struct files_struct *fsp, char *list,
454 size_t size)
456 SMB_STRUCT_STAT sbuf;
457 struct file_id id;
458 struct db_context *db;
460 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
462 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
463 return -1;
466 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
468 return xattr_tdb_listattr(db, &id, list, size);
472 * Worker routine for removexattr and fremovexattr
475 static int xattr_tdb_removeattr(struct db_context *db_ctx,
476 const struct file_id *id, const char *name)
478 NTSTATUS status;
479 struct db_record *rec;
480 struct tdb_xattrs *attribs;
481 uint32_t i;
483 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
485 if (rec == NULL) {
486 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
487 errno = EINVAL;
488 return -1;
491 status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
493 if (!NT_STATUS_IS_OK(status)) {
494 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
495 nt_errstr(status)));
496 TALLOC_FREE(rec);
497 return -1;
500 for (i=0; i<attribs->num_eas; i++) {
501 if (strcmp(attribs->eas[i].name, name) == 0) {
502 break;
506 if (i == attribs->num_eas) {
507 TALLOC_FREE(rec);
508 errno = ENOATTR;
509 return -1;
512 attribs->eas[i] =
513 attribs->eas[attribs->num_eas-1];
514 attribs->num_eas -= 1;
516 if (attribs->num_eas == 0) {
517 rec->delete_rec(rec);
518 TALLOC_FREE(rec);
519 return 0;
522 status = xattr_tdb_save_attrs(rec, attribs);
524 TALLOC_FREE(rec);
526 if (!NT_STATUS_IS_OK(status)) {
527 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
528 return -1;
531 return 0;
534 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
535 const char *path, const char *name)
537 SMB_STRUCT_STAT sbuf;
538 struct file_id id;
539 struct db_context *db;
541 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
543 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
544 return -1;
547 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
549 return xattr_tdb_removeattr(db, &id, name);
552 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
553 struct files_struct *fsp, const char *name)
555 SMB_STRUCT_STAT sbuf;
556 struct file_id id;
557 struct db_context *db;
559 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
561 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
562 return -1;
565 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
567 return xattr_tdb_removeattr(db, &id, name);
571 * Open the tdb file upon VFS_CONNECT
574 static bool xattr_tdb_init(int snum, struct db_context **p_db)
576 struct db_context *db;
577 const char *dbname;
578 char *def_dbname;
580 def_dbname = state_path("xattr.tdb");
581 if (def_dbname == NULL) {
582 errno = ENOSYS;
583 return false;
586 dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
588 /* now we know dbname is not NULL */
590 become_root();
591 db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
592 unbecome_root();
594 if (db == NULL) {
595 #if defined(ENOTSUP)
596 errno = ENOTSUP;
597 #else
598 errno = ENOSYS;
599 #endif
600 TALLOC_FREE(def_dbname);
601 return false;
604 *p_db = db;
605 TALLOC_FREE(def_dbname);
606 return true;
610 * On unlink we need to delete the tdb record
612 static int xattr_tdb_unlink(vfs_handle_struct *handle,
613 const struct smb_filename *smb_fname)
615 struct smb_filename *smb_fname_tmp = NULL;
616 struct file_id id;
617 struct db_context *db;
618 struct db_record *rec;
619 NTSTATUS status;
620 int ret = -1;
621 bool remove_record = false;
623 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
625 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
626 if (!NT_STATUS_IS_OK(status)) {
627 errno = map_errno_from_nt_status(status);
628 return -1;
631 if (lp_posix_pathnames()) {
632 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
633 } else {
634 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
636 if (ret == -1) {
637 goto out;
640 if (smb_fname_tmp->st.st_ex_nlink == 1) {
641 /* Only remove record on last link to file. */
642 remove_record = true;
645 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
647 if (ret == -1) {
648 goto out;
651 if (!remove_record) {
652 goto out;
655 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
657 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
660 * If rec == NULL there's not much we can do about it
663 if (rec != NULL) {
664 rec->delete_rec(rec);
665 TALLOC_FREE(rec);
668 out:
669 TALLOC_FREE(smb_fname_tmp);
670 return ret;
674 * On rmdir we need to delete the tdb record
676 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
678 SMB_STRUCT_STAT sbuf;
679 struct file_id id;
680 struct db_context *db;
681 struct db_record *rec;
682 int ret;
684 SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
686 if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
687 return -1;
690 ret = SMB_VFS_NEXT_RMDIR(handle, path);
692 if (ret == -1) {
693 return -1;
696 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
698 rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
701 * If rec == NULL there's not much we can do about it
704 if (rec != NULL) {
705 rec->delete_rec(rec);
706 TALLOC_FREE(rec);
709 return 0;
713 * Destructor for the VFS private data
716 static void close_xattr_db(void **data)
718 struct db_context **p_db = (struct db_context **)data;
719 TALLOC_FREE(*p_db);
722 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
723 const char *user)
725 fstring sname;
726 int res, snum;
727 struct db_context *db;
729 res = SMB_VFS_NEXT_CONNECT(handle, service, user);
730 if (res < 0) {
731 return res;
734 fstrcpy(sname, service);
735 snum = find_service(sname);
736 if (snum == -1) {
738 * Should not happen, but we should not fail just *here*.
740 return 0;
743 if (!xattr_tdb_init(snum, &db)) {
744 DEBUG(5, ("Could not init xattr tdb\n"));
745 lp_do_parameter(snum, "ea support", "False");
746 return 0;
749 lp_do_parameter(snum, "ea support", "True");
751 SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
752 struct db_context, return -1);
754 return 0;
757 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
758 .getxattr = xattr_tdb_getxattr,
759 .fgetxattr = xattr_tdb_fgetxattr,
760 .setxattr = xattr_tdb_setxattr,
761 .fsetxattr = xattr_tdb_fsetxattr,
762 .listxattr = xattr_tdb_listxattr,
763 .flistxattr = xattr_tdb_flistxattr,
764 .removexattr = xattr_tdb_removexattr,
765 .fremovexattr = xattr_tdb_fremovexattr,
766 .unlink = xattr_tdb_unlink,
767 .rmdir = xattr_tdb_rmdir,
768 .connect_fn = xattr_tdb_connect,
771 NTSTATUS vfs_xattr_tdb_init(void);
772 NTSTATUS vfs_xattr_tdb_init(void)
774 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
775 &vfs_xattr_tdb_fns);