libcli: Speed up sddl_decode_ace()
[samba.git] / source3 / lib / xattr_tdb.c
blob8c1cc7398c16002d80877b871b1215218d58f151
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(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(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();
184 struct file_id_buf buf;
186 DBG_DEBUG("xattr_tdb_getattr called for file %s, name %s\n",
187 file_id_str_buf(*id, &buf), name);
189 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
191 if (!NT_STATUS_IS_OK(status)) {
192 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
193 nt_errstr(status)));
194 TALLOC_FREE(frame);
195 errno = EINVAL;
196 return -1;
199 for (i=0; i<attribs->num_eas; i++) {
200 if (strcmp(attribs->eas[i].name, name) == 0) {
201 break;
205 if (i == attribs->num_eas) {
206 errno = ENOATTR;
207 goto fail;
210 *blob = attribs->eas[i].value;
211 talloc_steal(mem_ctx, blob->data);
212 result = attribs->eas[i].value.length;
214 fail:
215 TALLOC_FREE(frame);
216 return result;
220 * Worker routine for setxattr and fsetxattr
223 int xattr_tdb_setattr(struct db_context *db_ctx,
224 const struct file_id *id, const char *name,
225 const void *value, size_t size, int flags)
227 NTSTATUS status;
228 struct db_record *rec;
229 struct tdb_xattrs *attribs;
230 uint32_t i;
231 TDB_DATA data;
232 TALLOC_CTX *frame = talloc_stackframe();
233 struct file_id_buf buf;
235 DBG_DEBUG("xattr_tdb_setattr called for file %s, name %s\n",
236 file_id_str_buf(*id, &buf), name);
238 rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
240 if (rec == NULL) {
241 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
242 errno = EINVAL;
243 return -1;
246 data = dbwrap_record_get_value(rec);
248 status = xattr_tdb_pull_attrs(rec, &data, &attribs);
250 if (!NT_STATUS_IS_OK(status)) {
251 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
252 nt_errstr(status)));
253 TALLOC_FREE(frame);
254 return -1;
257 for (i=0; i<attribs->num_eas; i++) {
258 if (strcmp(attribs->eas[i].name, name) == 0) {
259 if (flags & XATTR_CREATE) {
260 TALLOC_FREE(frame);
261 errno = EEXIST;
262 return -1;
264 break;
268 if (i == attribs->num_eas) {
269 struct xattr_EA *tmp;
271 if (flags & XATTR_REPLACE) {
272 TALLOC_FREE(frame);
273 errno = ENOATTR;
274 return -1;
277 tmp = talloc_realloc(
278 attribs, attribs->eas, struct xattr_EA,
279 attribs->num_eas+ 1);
281 if (tmp == NULL) {
282 DEBUG(0, ("talloc_realloc failed\n"));
283 TALLOC_FREE(frame);
284 errno = ENOMEM;
285 return -1;
288 attribs->eas = tmp;
289 attribs->num_eas += 1;
292 attribs->eas[i].name = name;
293 attribs->eas[i].value.data = discard_const_p(uint8_t, value);
294 attribs->eas[i].value.length = size;
296 status = xattr_tdb_save_attrs(rec, attribs);
298 TALLOC_FREE(frame);
300 if (!NT_STATUS_IS_OK(status)) {
301 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
302 return -1;
305 return 0;
309 * Worker routine for listxattr and flistxattr
312 ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
313 const struct file_id *id, char *list,
314 size_t size)
316 NTSTATUS status;
317 struct tdb_xattrs *attribs;
318 uint32_t i;
319 size_t len = 0;
320 TALLOC_CTX *frame = talloc_stackframe();
322 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
324 if (!NT_STATUS_IS_OK(status) &&
325 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
327 DEBUG(0, ("xattr_tdb_fetch_attrs failed: %s\n",
328 nt_errstr(status)));
329 errno = EINVAL;
330 TALLOC_FREE(frame);
331 return -1;
334 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335 TALLOC_FREE(frame);
336 return 0;
339 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
340 attribs->num_eas));
342 for (i=0; i<attribs->num_eas; i++) {
343 size_t tmp;
345 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
346 attribs->eas[i].name));
348 tmp = strlen(attribs->eas[i].name);
351 * Try to protect against overflow
354 if (len + (tmp+1) < len) {
355 TALLOC_FREE(frame);
356 errno = EINVAL;
357 return -1;
361 * Take care of the terminating NULL
363 len += (tmp + 1);
366 if (len > size) {
367 TALLOC_FREE(frame);
368 errno = ERANGE;
369 return len;
372 len = 0;
374 for (i=0; i<attribs->num_eas; i++) {
375 strlcpy(list+len, attribs->eas[i].name,
376 size-len);
377 len += (strlen(attribs->eas[i].name) + 1);
380 TALLOC_FREE(frame);
381 return len;
385 * Worker routine for removexattr and fremovexattr
388 int xattr_tdb_removeattr(struct db_context *db_ctx,
389 const struct file_id *id, const char *name)
391 NTSTATUS status;
392 struct db_record *rec;
393 struct tdb_xattrs *attribs;
394 uint32_t i;
395 TDB_DATA value;
397 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
399 if (rec == NULL) {
400 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
401 errno = EINVAL;
402 return -1;
405 value = dbwrap_record_get_value(rec);
407 status = xattr_tdb_pull_attrs(rec, &value, &attribs);
409 if (!NT_STATUS_IS_OK(status)) {
410 DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
411 nt_errstr(status)));
412 TALLOC_FREE(rec);
413 return -1;
416 for (i=0; i<attribs->num_eas; i++) {
417 if (strcmp(attribs->eas[i].name, name) == 0) {
418 break;
422 if (i == attribs->num_eas) {
423 TALLOC_FREE(rec);
424 errno = ENOATTR;
425 return -1;
428 attribs->eas[i] =
429 attribs->eas[attribs->num_eas-1];
430 attribs->num_eas -= 1;
432 if (attribs->num_eas == 0) {
433 dbwrap_record_delete(rec);
434 TALLOC_FREE(rec);
435 return 0;
438 status = xattr_tdb_save_attrs(rec, attribs);
440 TALLOC_FREE(rec);
442 if (!NT_STATUS_IS_OK(status)) {
443 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
444 return -1;
447 return 0;
451 * Worker routine for unlink and rmdir
454 void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
455 const struct file_id *id)
457 struct db_record *rec;
458 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
461 * If rec == NULL there's not much we can do about it
464 if (rec != NULL) {
465 dbwrap_record_delete(rec);
466 TALLOC_FREE(rec);