2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Andrew Bartlett 2011
6 * extracted from vfs_xattr_tdb by
8 * Copyright (C) Volker Lendecke, 2007
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #include "source3/include/includes.h"
25 #include "system/filesys.h"
26 #include "librpc/gen_ndr/xattr.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
28 #include "librpc/gen_ndr/file_id.h"
29 #include "dbwrap/dbwrap.h"
30 #include "lib/util/util_tdb.h"
31 #include "source3/lib/xattr_tdb.h"
32 #include "source3/lib/file_id.h"
35 #define DBGC_CLASS DBGC_VFS
38 * unmarshall tdb_xattrs
41 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
43 struct tdb_xattrs **presult)
46 enum ndr_err_code ndr_err;
47 struct tdb_xattrs *result;
49 if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
50 return NT_STATUS_NO_MEMORY;
53 if (data->dsize == 0) {
58 blob = data_blob_const(data->dptr, data->dsize);
60 ndr_err = ndr_pull_struct_blob(&blob, result, result,
61 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
63 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
64 DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
65 ndr_errstr(ndr_err)));
67 return ndr_map_error2ntstatus(ndr_err);
78 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
79 const struct tdb_xattrs *attribs,
83 enum ndr_err_code ndr_err;
85 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
86 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
88 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
89 DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
90 ndr_errstr(ndr_err)));
91 return ndr_map_error2ntstatus(ndr_err);
94 *data = make_tdb_data(blob.data, blob.length);
99 * Load tdb_xattrs for a file from the tdb
102 static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
103 struct db_context *db_ctx,
104 const struct file_id *id,
105 struct tdb_xattrs **presult)
111 /* For backwards compatibility only store the dev/inode. */
112 push_file_id_16((char *)id_buf, id);
114 status = dbwrap_fetch(db_ctx, mem_ctx,
115 make_tdb_data(id_buf, sizeof(id_buf)),
117 if (!NT_STATUS_IS_OK(status)) {
118 return NT_STATUS_INTERNAL_DB_CORRUPTION;
121 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
122 TALLOC_FREE(data.dptr);
127 * fetch_lock the tdb_ea record for a file
130 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
131 struct db_context *db_ctx,
132 const struct file_id *id)
136 /* For backwards compatibility only store the dev/inode. */
137 push_file_id_16((char *)id_buf, id);
138 return dbwrap_fetch_locked(db_ctx, mem_ctx,
139 make_tdb_data(id_buf, sizeof(id_buf)));
143 * Save tdb_xattrs to a previously fetch_locked record
146 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
147 const struct tdb_xattrs *attribs)
149 TDB_DATA data = tdb_null;
152 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
154 if (!NT_STATUS_IS_OK(status)) {
155 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
160 status = dbwrap_record_store(rec, data, 0);
162 TALLOC_FREE(data.dptr);
168 * Worker routine for getxattr and fgetxattr
171 ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
173 const struct file_id *id,
174 const char *name, DATA_BLOB *blob)
176 struct tdb_xattrs *attribs;
180 TALLOC_CTX *frame = talloc_stackframe();
182 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
183 file_id_string(frame, id), name));
185 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
187 if (!NT_STATUS_IS_OK(status)) {
188 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
195 for (i=0; i<attribs->num_eas; i++) {
196 if (strcmp(attribs->eas[i].name, name) == 0) {
201 if (i == attribs->num_eas) {
206 *blob = attribs->eas[i].value;
207 talloc_steal(mem_ctx, blob->data);
208 result = attribs->eas[i].value.length;
216 * Worker routine for setxattr and fsetxattr
219 int xattr_tdb_setattr(struct db_context *db_ctx,
220 const struct file_id *id, const char *name,
221 const void *value, size_t size, int flags)
224 struct db_record *rec;
225 struct tdb_xattrs *attribs;
228 TALLOC_CTX *frame = talloc_stackframe();
230 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
231 file_id_string(frame, id), name));
233 rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
236 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
241 data = dbwrap_record_get_value(rec);
243 status = xattr_tdb_pull_attrs(rec, &data, &attribs);
245 if (!NT_STATUS_IS_OK(status)) {
246 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
252 for (i=0; i<attribs->num_eas; i++) {
253 if (strcmp(attribs->eas[i].name, name) == 0) {
254 if (flags & XATTR_CREATE) {
263 if (i == attribs->num_eas) {
264 struct xattr_EA *tmp;
266 if (flags & XATTR_REPLACE) {
272 tmp = talloc_realloc(
273 attribs, attribs->eas, struct xattr_EA,
274 attribs->num_eas+ 1);
277 DEBUG(0, ("talloc_realloc failed\n"));
284 attribs->num_eas += 1;
287 attribs->eas[i].name = name;
288 attribs->eas[i].value.data = discard_const_p(uint8_t, value);
289 attribs->eas[i].value.length = size;
291 status = xattr_tdb_save_attrs(rec, attribs);
295 if (!NT_STATUS_IS_OK(status)) {
296 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
304 * Worker routine for listxattr and flistxattr
307 ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
308 const struct file_id *id, char *list,
312 struct tdb_xattrs *attribs;
315 TALLOC_CTX *frame = talloc_stackframe();
317 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
319 if (!NT_STATUS_IS_OK(status)) {
320 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
327 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
330 for (i=0; i<attribs->num_eas; i++) {
333 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
334 attribs->eas[i].name));
336 tmp = strlen(attribs->eas[i].name);
339 * Try to protect against overflow
342 if (len + (tmp+1) < len) {
349 * Take care of the terminating NULL
362 for (i=0; i<attribs->num_eas; i++) {
363 strlcpy(list+len, attribs->eas[i].name,
365 len += (strlen(attribs->eas[i].name) + 1);
373 * Worker routine for removexattr and fremovexattr
376 int xattr_tdb_removeattr(struct db_context *db_ctx,
377 const struct file_id *id, const char *name)
380 struct db_record *rec;
381 struct tdb_xattrs *attribs;
385 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
388 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
393 value = dbwrap_record_get_value(rec);
395 status = xattr_tdb_pull_attrs(rec, &value, &attribs);
397 if (!NT_STATUS_IS_OK(status)) {
398 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
404 for (i=0; i<attribs->num_eas; i++) {
405 if (strcmp(attribs->eas[i].name, name) == 0) {
410 if (i == attribs->num_eas) {
417 attribs->eas[attribs->num_eas-1];
418 attribs->num_eas -= 1;
420 if (attribs->num_eas == 0) {
421 dbwrap_record_delete(rec);
426 status = xattr_tdb_save_attrs(rec, attribs);
430 if (!NT_STATUS_IS_OK(status)) {
431 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
439 * Worker routine for unlink and rmdir
442 void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
443 const struct file_id *id)
445 struct db_record *rec;
446 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
449 * If rec == NULL there's not much we can do about it
453 dbwrap_record_delete(rec);