wafsamba: remove tru64cc.py as it's not compatible with waf 2
[Samba.git] / source3 / lib / xattr_tdb.c
blobf3a2e19bf5d47fc51e9939f5eea7dc8e70e2475e
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 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
119 return status;
121 return NT_STATUS_INTERNAL_DB_CORRUPTION;
124 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
125 TALLOC_FREE(data.dptr);
126 return status;
130 * fetch_lock the tdb_ea record for a file
133 static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
134 struct db_context *db_ctx,
135 const struct file_id *id)
137 uint8_t id_buf[16];
139 /* For backwards compatibility only store the dev/inode. */
140 push_file_id_16((char *)id_buf, id);
141 return dbwrap_fetch_locked(db_ctx, mem_ctx,
142 make_tdb_data(id_buf, sizeof(id_buf)));
146 * Save tdb_xattrs to a previously fetch_locked record
149 static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
150 const struct tdb_xattrs *attribs)
152 TDB_DATA data = tdb_null;
153 NTSTATUS status;
155 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
157 if (!NT_STATUS_IS_OK(status)) {
158 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
159 nt_errstr(status)));
160 return status;
163 status = dbwrap_record_store(rec, data, 0);
165 TALLOC_FREE(data.dptr);
167 return status;
171 * Worker routine for getxattr and fgetxattr
174 ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
175 TALLOC_CTX *mem_ctx,
176 const struct file_id *id,
177 const char *name, DATA_BLOB *blob)
179 struct tdb_xattrs *attribs;
180 uint32_t i;
181 ssize_t result = -1;
182 NTSTATUS status;
183 TALLOC_CTX *frame = talloc_stackframe();
185 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
186 file_id_string(frame, id), name));
188 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
190 if (!NT_STATUS_IS_OK(status)) {
191 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
192 nt_errstr(status)));
193 TALLOC_FREE(frame);
194 errno = EINVAL;
195 return -1;
198 for (i=0; i<attribs->num_eas; i++) {
199 if (strcmp(attribs->eas[i].name, name) == 0) {
200 break;
204 if (i == attribs->num_eas) {
205 errno = ENOATTR;
206 goto fail;
209 *blob = attribs->eas[i].value;
210 talloc_steal(mem_ctx, blob->data);
211 result = attribs->eas[i].value.length;
213 fail:
214 TALLOC_FREE(frame);
215 return result;
219 * Worker routine for setxattr and fsetxattr
222 int xattr_tdb_setattr(struct db_context *db_ctx,
223 const struct file_id *id, const char *name,
224 const void *value, size_t size, int flags)
226 NTSTATUS status;
227 struct db_record *rec;
228 struct tdb_xattrs *attribs;
229 uint32_t i;
230 TDB_DATA data;
231 TALLOC_CTX *frame = talloc_stackframe();
233 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
234 file_id_string(frame, id), name));
236 rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
238 if (rec == NULL) {
239 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
240 errno = EINVAL;
241 return -1;
244 data = dbwrap_record_get_value(rec);
246 status = xattr_tdb_pull_attrs(rec, &data, &attribs);
248 if (!NT_STATUS_IS_OK(status)) {
249 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
250 nt_errstr(status)));
251 TALLOC_FREE(frame);
252 return -1;
255 for (i=0; i<attribs->num_eas; i++) {
256 if (strcmp(attribs->eas[i].name, name) == 0) {
257 if (flags & XATTR_CREATE) {
258 TALLOC_FREE(frame);
259 errno = EEXIST;
260 return -1;
262 break;
266 if (i == attribs->num_eas) {
267 struct xattr_EA *tmp;
269 if (flags & XATTR_REPLACE) {
270 TALLOC_FREE(frame);
271 errno = ENOATTR;
272 return -1;
275 tmp = talloc_realloc(
276 attribs, attribs->eas, struct xattr_EA,
277 attribs->num_eas+ 1);
279 if (tmp == NULL) {
280 DEBUG(0, ("talloc_realloc failed\n"));
281 TALLOC_FREE(frame);
282 errno = ENOMEM;
283 return -1;
286 attribs->eas = tmp;
287 attribs->num_eas += 1;
290 attribs->eas[i].name = name;
291 attribs->eas[i].value.data = discard_const_p(uint8_t, value);
292 attribs->eas[i].value.length = size;
294 status = xattr_tdb_save_attrs(rec, attribs);
296 TALLOC_FREE(frame);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
300 return -1;
303 return 0;
307 * Worker routine for listxattr and flistxattr
310 ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
311 const struct file_id *id, char *list,
312 size_t size)
314 NTSTATUS status;
315 struct tdb_xattrs *attribs;
316 uint32_t i;
317 size_t len = 0;
318 TALLOC_CTX *frame = talloc_stackframe();
320 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
322 if (!NT_STATUS_IS_OK(status) &&
323 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
325 DEBUG(0, ("xattr_tdb_fetch_attrs failed: %s\n",
326 nt_errstr(status)));
327 errno = EINVAL;
328 TALLOC_FREE(frame);
329 return -1;
332 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
333 TALLOC_FREE(frame);
334 return 0;
337 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
338 attribs->num_eas));
340 for (i=0; i<attribs->num_eas; i++) {
341 size_t tmp;
343 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
344 attribs->eas[i].name));
346 tmp = strlen(attribs->eas[i].name);
349 * Try to protect against overflow
352 if (len + (tmp+1) < len) {
353 TALLOC_FREE(frame);
354 errno = EINVAL;
355 return -1;
359 * Take care of the terminating NULL
361 len += (tmp + 1);
364 if (len > size) {
365 TALLOC_FREE(frame);
366 errno = ERANGE;
367 return len;
370 len = 0;
372 for (i=0; i<attribs->num_eas; i++) {
373 strlcpy(list+len, attribs->eas[i].name,
374 size-len);
375 len += (strlen(attribs->eas[i].name) + 1);
378 TALLOC_FREE(frame);
379 return len;
383 * Worker routine for removexattr and fremovexattr
386 int xattr_tdb_removeattr(struct db_context *db_ctx,
387 const struct file_id *id, const char *name)
389 NTSTATUS status;
390 struct db_record *rec;
391 struct tdb_xattrs *attribs;
392 uint32_t i;
393 TDB_DATA value;
395 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
397 if (rec == NULL) {
398 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
399 errno = EINVAL;
400 return -1;
403 value = dbwrap_record_get_value(rec);
405 status = xattr_tdb_pull_attrs(rec, &value, &attribs);
407 if (!NT_STATUS_IS_OK(status)) {
408 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
409 nt_errstr(status)));
410 TALLOC_FREE(rec);
411 return -1;
414 for (i=0; i<attribs->num_eas; i++) {
415 if (strcmp(attribs->eas[i].name, name) == 0) {
416 break;
420 if (i == attribs->num_eas) {
421 TALLOC_FREE(rec);
422 errno = ENOATTR;
423 return -1;
426 attribs->eas[i] =
427 attribs->eas[attribs->num_eas-1];
428 attribs->num_eas -= 1;
430 if (attribs->num_eas == 0) {
431 dbwrap_record_delete(rec);
432 TALLOC_FREE(rec);
433 return 0;
436 status = xattr_tdb_save_attrs(rec, attribs);
438 TALLOC_FREE(rec);
440 if (!NT_STATUS_IS_OK(status)) {
441 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
442 return -1;
445 return 0;
449 * Worker routine for unlink and rmdir
452 void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
453 const struct file_id *id)
455 struct db_record *rec;
456 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
459 * If rec == NULL there's not much we can do about it
462 if (rec != NULL) {
463 dbwrap_record_delete(rec);
464 TALLOC_FREE(rec);