source: vendor/current/source3/lib/xattr_tdb.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.5 KB
Line 
1/*
2 * Store posix-level xattrs in a tdb
3 *
4 * Copyright (C) Andrew Bartlett 2011
5 *
6 * extracted from vfs_xattr_tdb by
7 *
8 * Copyright (C) Volker Lendecke, 2007
9 *
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.
14 *
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.
19 *
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/>.
22 */
23
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"
33
34#undef DBGC_CLASS
35#define DBGC_CLASS DBGC_VFS
36
37/*
38 * unmarshall tdb_xattrs
39 */
40
41static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
42 const TDB_DATA *data,
43 struct tdb_xattrs **presult)
44{
45 DATA_BLOB blob;
46 enum ndr_err_code ndr_err;
47 struct tdb_xattrs *result;
48
49 if (!(result = talloc_zero(mem_ctx, struct tdb_xattrs))) {
50 return NT_STATUS_NO_MEMORY;
51 }
52
53 if (data->dsize == 0) {
54 *presult = result;
55 return NT_STATUS_OK;
56 }
57
58 blob = data_blob_const(data->dptr, data->dsize);
59
60 ndr_err = ndr_pull_struct_blob(&blob, result, result,
61 (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
62
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);
68 }
69
70 *presult = result;
71 return NT_STATUS_OK;
72}
73
74/*
75 * marshall tdb_xattrs
76 */
77
78static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
79 const struct tdb_xattrs *attribs,
80 TDB_DATA *data)
81{
82 DATA_BLOB blob;
83 enum ndr_err_code ndr_err;
84
85 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, attribs,
86 (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
87
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);
92 }
93
94 *data = make_tdb_data(blob.data, blob.length);
95 return NT_STATUS_OK;
96}
97
98/*
99 * Load tdb_xattrs for a file from the tdb
100 */
101
102static 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)
106{
107 uint8_t id_buf[16];
108 NTSTATUS status;
109 TDB_DATA data;
110
111 /* For backwards compatibility only store the dev/inode. */
112 push_file_id_16((char *)id_buf, id);
113
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;
119 }
120
121 status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
122 TALLOC_FREE(data.dptr);
123 return status;
124}
125
126/*
127 * fetch_lock the tdb_ea record for a file
128 */
129
130static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
131 struct db_context *db_ctx,
132 const struct file_id *id)
133{
134 uint8_t id_buf[16];
135
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)));
140}
141
142/*
143 * Save tdb_xattrs to a previously fetch_locked record
144 */
145
146static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
147 const struct tdb_xattrs *attribs)
148{
149 TDB_DATA data = tdb_null;
150 NTSTATUS status;
151
152 status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
153
154 if (!NT_STATUS_IS_OK(status)) {
155 DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
156 nt_errstr(status)));
157 return status;
158 }
159
160 status = dbwrap_record_store(rec, data, 0);
161
162 TALLOC_FREE(data.dptr);
163
164 return status;
165}
166
167/*
168 * Worker routine for getxattr and fgetxattr
169 */
170
171ssize_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)
175{
176 struct tdb_xattrs *attribs;
177 uint32_t i;
178 ssize_t result = -1;
179 NTSTATUS status;
180 TALLOC_CTX *frame = talloc_stackframe();
181
182 DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
183 file_id_string(frame, id), name));
184
185 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
186
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;
193 }
194
195 for (i=0; i<attribs->num_eas; i++) {
196 if (strcmp(attribs->eas[i].name, name) == 0) {
197 break;
198 }
199 }
200
201 if (i == attribs->num_eas) {
202 errno = ENOATTR;
203 goto fail;
204 }
205
206 *blob = attribs->eas[i].value;
207 talloc_steal(mem_ctx, blob->data);
208 result = attribs->eas[i].value.length;
209
210 fail:
211 TALLOC_FREE(frame);
212 return result;
213}
214
215/*
216 * Worker routine for setxattr and fsetxattr
217 */
218
219int 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)
222{
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();
229
230 DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
231 file_id_string(frame, id), name));
232
233 rec = xattr_tdb_lock_attrs(frame, db_ctx, id);
234
235 if (rec == NULL) {
236 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
237 errno = EINVAL;
238 return -1;
239 }
240
241 data = dbwrap_record_get_value(rec);
242
243 status = xattr_tdb_pull_attrs(rec, &data, &attribs);
244
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;
250 }
251
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;
258 }
259 break;
260 }
261 }
262
263 if (i == attribs->num_eas) {
264 struct xattr_EA *tmp;
265
266 if (flags & XATTR_REPLACE) {
267 TALLOC_FREE(frame);
268 errno = ENOATTR;
269 return -1;
270 }
271
272 tmp = talloc_realloc(
273 attribs, attribs->eas, struct xattr_EA,
274 attribs->num_eas+ 1);
275
276 if (tmp == NULL) {
277 DEBUG(0, ("talloc_realloc failed\n"));
278 TALLOC_FREE(frame);
279 errno = ENOMEM;
280 return -1;
281 }
282
283 attribs->eas = tmp;
284 attribs->num_eas += 1;
285 }
286
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;
290
291 status = xattr_tdb_save_attrs(rec, attribs);
292
293 TALLOC_FREE(frame);
294
295 if (!NT_STATUS_IS_OK(status)) {
296 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
297 return -1;
298 }
299
300 return 0;
301}
302
303/*
304 * Worker routine for listxattr and flistxattr
305 */
306
307ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
308 const struct file_id *id, char *list,
309 size_t size)
310{
311 NTSTATUS status;
312 struct tdb_xattrs *attribs;
313 uint32_t i;
314 size_t len = 0;
315 TALLOC_CTX *frame = talloc_stackframe();
316
317 status = xattr_tdb_load_attrs(frame, db_ctx, id, &attribs);
318
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;
325 }
326
327 DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
328 attribs->num_eas));
329
330 for (i=0; i<attribs->num_eas; i++) {
331 size_t tmp;
332
333 DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
334 attribs->eas[i].name));
335
336 tmp = strlen(attribs->eas[i].name);
337
338 /*
339 * Try to protect against overflow
340 */
341
342 if (len + (tmp+1) < len) {
343 TALLOC_FREE(frame);
344 errno = EINVAL;
345 return -1;
346 }
347
348 /*
349 * Take care of the terminating NULL
350 */
351 len += (tmp + 1);
352 }
353
354 if (len > size) {
355 TALLOC_FREE(frame);
356 errno = ERANGE;
357 return len;
358 }
359
360 len = 0;
361
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);
366 }
367
368 TALLOC_FREE(frame);
369 return len;
370}
371
372/*
373 * Worker routine for removexattr and fremovexattr
374 */
375
376int xattr_tdb_removeattr(struct db_context *db_ctx,
377 const struct file_id *id, const char *name)
378{
379 NTSTATUS status;
380 struct db_record *rec;
381 struct tdb_xattrs *attribs;
382 uint32_t i;
383 TDB_DATA value;
384
385 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
386
387 if (rec == NULL) {
388 DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
389 errno = EINVAL;
390 return -1;
391 }
392
393 value = dbwrap_record_get_value(rec);
394
395 status = xattr_tdb_pull_attrs(rec, &value, &attribs);
396
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;
402 }
403
404 for (i=0; i<attribs->num_eas; i++) {
405 if (strcmp(attribs->eas[i].name, name) == 0) {
406 break;
407 }
408 }
409
410 if (i == attribs->num_eas) {
411 TALLOC_FREE(rec);
412 errno = ENOATTR;
413 return -1;
414 }
415
416 attribs->eas[i] =
417 attribs->eas[attribs->num_eas-1];
418 attribs->num_eas -= 1;
419
420 if (attribs->num_eas == 0) {
421 dbwrap_record_delete(rec);
422 TALLOC_FREE(rec);
423 return 0;
424 }
425
426 status = xattr_tdb_save_attrs(rec, attribs);
427
428 TALLOC_FREE(rec);
429
430 if (!NT_STATUS_IS_OK(status)) {
431 DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
432 return -1;
433 }
434
435 return 0;
436}
437
438/*
439 * Worker routine for unlink and rmdir
440 */
441
442void xattr_tdb_remove_all_attrs(struct db_context *db_ctx,
443 const struct file_id *id)
444{
445 struct db_record *rec;
446 rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
447
448 /*
449 * If rec == NULL there's not much we can do about it
450 */
451
452 if (rec != NULL) {
453 dbwrap_record_delete(rec);
454 TALLOC_FREE(rec);
455 }
456}
Note: See TracBrowser for help on using the repository browser.