s3:locking:brlock: improve the comment for the brl self cleaning code
[Samba/gebeck_regimport.git] / source3 / lib / xattr_tdb.c
blob34afbe29291f532d2c0930ea2f974f787ccf62f7
1 /*
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"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_VFS
38 * unmarshall tdb_xattrs
41 static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
42 const TDB_DATA *data,
43 struct tdb_xattrs **presult)
45 DATA_BLOB blob;
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) {
54 *presult = result;
55 return NT_STATUS_OK;
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)));
66 TALLOC_FREE(result);
67 return ndr_map_error2ntstatus(ndr_err);
70 *presult = result;
71 return NT_STATUS_OK;
75 * marshall tdb_xattrs
78 static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
79 const struct tdb_xattrs *attribs,
80 TDB_DATA *data)
82 DATA_BLOB blob;
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);
95 return NT_STATUS_OK;
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)
107 uint8_t id_buf[16];
108 NTSTATUS status;
109 TDB_DATA data;
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)),
116 &data);
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);
123 return status;
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)
134 uint8_t id_buf[16];
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;
150 NTSTATUS status;
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",
156 nt_errstr(status)));
157 return status;
160 status = dbwrap_record_store(rec, data, 0);
162 TALLOC_FREE(data.dptr);
164 return status;
168 * Worker routine for getxattr and fgetxattr
171 ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
172 TALLOC_CTX *mem_ctx,
173 const struct file_id *id,
174 const char *name, DATA_BLOB *blob)
176 struct tdb_xattrs *attribs;
177 uint32_t i;
178 ssize_t result = -1;
179 NTSTATUS status;
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",
189 nt_errstr(status)));
190 TALLOC_FREE(frame);
191 errno = EINVAL;
192 return -1;
195 for (i=0; i<attribs->num_eas; i++) {
196 if (strcmp(attribs->eas[i].name, name) == 0) {
197 break;
201 if (i == attribs->num_eas) {
202 errno = ENOATTR;
203 goto fail;
206 *blob = attribs->eas[i].value;
207 talloc_steal(mem_ctx, blob->data);
208 result = attribs->eas[i].value.length;
210 fail:
211 TALLOC_FREE(frame);
212 return result;
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)
223 NTSTATUS status;
224 struct db_record *rec;
225 struct tdb_xattrs *attribs;
226 uint32_t i;
227 TDB_DATA data;
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);
235 if (rec == NULL) {
236 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
237 errno = EINVAL;
238 return -1;
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",
247 nt_errstr(status)));
248 TALLOC_FREE(frame);
249 return -1;
252 for (i=0; i<attribs->num_eas; i++) {
253 if (strcmp(attribs->eas[i].name, name) == 0) {
254 if (flags & XATTR_CREATE) {
255 TALLOC_FREE(frame);
256 errno = EEXIST;
257 return -1;
259 break;
263 if (i == attribs->num_eas) {
264 struct xattr_EA *tmp;
266 if (flags & XATTR_REPLACE) {
267 TALLOC_FREE(frame);
268 errno = ENOATTR;
269 return -1;
272 tmp = talloc_realloc(
273 attribs, attribs->eas, struct xattr_EA,
274 attribs->num_eas+ 1);
276 if (tmp == NULL) {
277 DEBUG(0, ("talloc_realloc failed\n"));
278 TALLOC_FREE(frame);
279 errno = ENOMEM;
280 return -1;
283 attribs->eas = tmp;
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);
293 TALLOC_FREE(frame);
295 if (!NT_STATUS_IS_OK(status)) {
296 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
297 return -1;
300 return 0;
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,
309 size_t size)
311 NTSTATUS status;
312 struct tdb_xattrs *attribs;
313 uint32_t i;
314 size_t len = 0;
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",
321 nt_errstr(status)));
322 errno = EINVAL;
323 TALLOC_FREE(frame);
324 return -1;
327 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
328 attribs->num_eas));
330 for (i=0; i<attribs->num_eas; i++) {
331 size_t tmp;
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) {
343 TALLOC_FREE(frame);
344 errno = EINVAL;
345 return -1;
349 * Take care of the terminating NULL
351 len += (tmp + 1);
354 if (len > size) {
355 TALLOC_FREE(frame);
356 errno = ERANGE;
357 return len;
360 len = 0;
362 for (i=0; i<attribs->num_eas; i++) {
363 strlcpy(list+len, attribs->eas[i].name,
364 size-len);
365 len += (strlen(attribs->eas[i].name) + 1);
368 TALLOC_FREE(frame);
369 return len;
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)
379 NTSTATUS status;
380 struct db_record *rec;
381 struct tdb_xattrs *attribs;
382 uint32_t i;
383 TDB_DATA value;
385 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
387 if (rec == NULL) {
388 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
389 errno = EINVAL;
390 return -1;
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",
399 nt_errstr(status)));
400 TALLOC_FREE(rec);
401 return -1;
404 for (i=0; i<attribs->num_eas; i++) {
405 if (strcmp(attribs->eas[i].name, name) == 0) {
406 break;
410 if (i == attribs->num_eas) {
411 TALLOC_FREE(rec);
412 errno = ENOATTR;
413 return -1;
416 attribs->eas[i] =
417 attribs->eas[attribs->num_eas-1];
418 attribs->num_eas -= 1;
420 if (attribs->num_eas == 0) {
421 dbwrap_record_delete(rec);
422 TALLOC_FREE(rec);
423 return 0;
426 status = xattr_tdb_save_attrs(rec, attribs);
428 TALLOC_FREE(rec);
430 if (!NT_STATUS_IS_OK(status)) {
431 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
432 return -1;
435 return 0;
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
452 if (rec != NULL) {
453 dbwrap_record_delete(rec);
454 TALLOC_FREE(rec);