sysquota: we need to list nfs4 as a separate fs name for the sys_get_nfs_quota backend
[kai/samba.git] / source3 / lib / xattr_tdb.c
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
41 static 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
78 static 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
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)
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
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)
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
146 static 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
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)
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
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)
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
307 ssize_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
376 int 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
442 void 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 }