r12696: Reduce the size of include/structs.h
[ab/samba.git/.git] / source4 / ntvfs / posix / pvfs_xattr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - xattr support
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25
26 /*
27   pull a xattr as a blob
28 */
29 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
30                                 TALLOC_CTX *mem_ctx,
31                                 const char *attr_name, 
32                                 const char *fname, 
33                                 int fd, 
34                                 size_t estimated_size,
35                                 DATA_BLOB *blob)
36 {
37         NTSTATUS status;
38
39         if (pvfs->ea_db) {
40                 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname, 
41                                            fd, estimated_size, blob);
42         }
43
44         status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname, 
45                                         fd, estimated_size, blob);
46
47         /* if the filesystem doesn't support them, then tell pvfs not to try again */
48         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
49                 DEBUG(5,("pvfs_xattr: xattr not supported in filesystem\n"));
50                 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
51                 status = NT_STATUS_NOT_FOUND;
52         }
53
54         return status;
55 }
56
57 /*
58   push a xattr as a blob
59 */
60 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
61                                 const char *attr_name, 
62                                 const char *fname, 
63                                 int fd, 
64                                 const DATA_BLOB *blob)
65 {
66         if (pvfs->ea_db) {
67                 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
68         }
69         return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
70 }
71
72
73 /*
74   delete a xattr
75 */
76 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, 
77                              const char *fname, int fd)
78 {
79         if (pvfs->ea_db) {
80                 return delete_xattr_tdb(pvfs, attr_name, fname, fd);
81         }
82         return delete_xattr_system(pvfs, attr_name, fname, fd);
83 }
84
85 /*
86   a hook called on unlink - allows the tdb xattr backend to cleanup
87 */
88 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
89 {
90         if (pvfs->ea_db) {
91                 return unlink_xattr_tdb(pvfs, fname);
92         }
93         return unlink_xattr_system(pvfs, fname);
94 }
95
96
97 /*
98   load a NDR structure from a xattr
99 */
100 static NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
101                                     TALLOC_CTX *mem_ctx,
102                                     const char *fname, int fd, const char *attr_name,
103                                     void *p, ndr_pull_flags_fn_t pull_fn)
104 {
105         NTSTATUS status;
106         DATA_BLOB blob;
107
108         status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname, 
109                                  fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
110         if (!NT_STATUS_IS_OK(status)) {
111                 return status;
112         }
113
114         /* pull the blob */
115         status = ndr_pull_struct_blob(&blob, mem_ctx, p, pull_fn);
116
117         data_blob_free(&blob);
118
119         return status;
120 }
121
122 /*
123   save a NDR structure into a xattr
124 */
125 static NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
126                                     const char *fname, int fd, const char *attr_name, 
127                                     void *p, ndr_push_flags_fn_t push_fn)
128 {
129         TALLOC_CTX *mem_ctx = talloc_new(NULL);
130         DATA_BLOB blob;
131         NTSTATUS status;
132
133         status = ndr_push_struct_blob(&blob, mem_ctx, p, push_fn);
134         if (!NT_STATUS_IS_OK(status)) {
135                 talloc_free(mem_ctx);
136                 return status;
137         }
138
139         status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
140         talloc_free(mem_ctx);
141
142         return status;
143 }
144
145
146 /*
147   fill in file attributes from extended attributes
148 */
149 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
150 {
151         NTSTATUS status;
152         struct xattr_DosAttrib attrib;
153         TALLOC_CTX *mem_ctx = talloc_new(name);
154         struct xattr_DosInfo1 *info1;
155         struct xattr_DosInfo2 *info2;
156
157         if (name->stream_name != NULL) {
158                 name->stream_exists = False;
159         } else {
160                 name->stream_exists = True;
161         }
162
163         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
164                 return NT_STATUS_OK;
165         }
166
167         status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, 
168                                      fd, XATTR_DOSATTRIB_NAME,
169                                      &attrib, 
170                                      (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
171
172         /* not having a DosAttrib is not an error */
173         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
174                 talloc_free(mem_ctx);
175                 return pvfs_stream_info(pvfs, name, fd);
176         }
177
178         if (!NT_STATUS_IS_OK(status)) {
179                 talloc_free(mem_ctx);
180                 return status;
181         }
182
183         switch (attrib.version) {
184         case 1:
185                 info1 = &attrib.info.info1;
186                 name->dos.attrib = pvfs_attrib_normalise(info1->attrib, 
187                                                          name->st.st_mode);
188                 name->dos.ea_size = info1->ea_size;
189                 if (name->st.st_size == info1->size) {
190                         name->dos.alloc_size = 
191                                 pvfs_round_alloc_size(pvfs, info1->alloc_size);
192                 }
193                 if (!null_nttime(info1->create_time)) {
194                         name->dos.create_time = info1->create_time;
195                 }
196                 if (!null_nttime(info1->change_time)) {
197                         name->dos.change_time = info1->change_time;
198                 }
199                 name->dos.flags = 0;
200                 break;
201
202         case 2:
203                 info2 = &attrib.info.info2;
204                 name->dos.attrib = pvfs_attrib_normalise(info2->attrib, 
205                                                          name->st.st_mode);
206                 name->dos.ea_size = info2->ea_size;
207                 if (name->st.st_size == info2->size) {
208                         name->dos.alloc_size = 
209                                 pvfs_round_alloc_size(pvfs, info2->alloc_size);
210                 }
211                 if (!null_nttime(info2->create_time)) {
212                         name->dos.create_time = info2->create_time;
213                 }
214                 if (!null_nttime(info2->change_time)) {
215                         name->dos.change_time = info2->change_time;
216                 }
217                 name->dos.flags = info2->flags;
218                 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
219                         name->dos.write_time = info2->write_time;
220                 }
221                 break;
222
223         default:
224                 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
225                          attrib.version, name->full_name));
226                 talloc_free(mem_ctx);
227                 return NT_STATUS_INVALID_LEVEL;
228         }
229         talloc_free(mem_ctx);
230         
231         status = pvfs_stream_info(pvfs, name, fd);
232
233         return status;
234 }
235
236
237 /*
238   save the file attribute into the xattr
239 */
240 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
241 {
242         struct xattr_DosAttrib attrib;
243         struct xattr_DosInfo2 *info2;
244
245         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
246                 return NT_STATUS_OK;
247         }
248
249         attrib.version = 2;
250         info2 = &attrib.info.info2;
251
252         name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
253
254         info2->attrib      = name->dos.attrib;
255         info2->ea_size     = name->dos.ea_size;
256         info2->size        = name->st.st_size;
257         info2->alloc_size  = name->dos.alloc_size;
258         info2->create_time = name->dos.create_time;
259         info2->change_time = name->dos.change_time;
260         info2->write_time  = name->dos.write_time;
261         info2->flags       = name->dos.flags;
262         info2->name        = "";
263
264         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
265                                    XATTR_DOSATTRIB_NAME, &attrib, 
266                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
267 }
268
269
270 /*
271   load the set of DOS EAs
272 */
273 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
274                           struct xattr_DosEAs *eas)
275 {
276         NTSTATUS status;
277         ZERO_STRUCTP(eas);
278         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
279                 return NT_STATUS_OK;
280         }
281         status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
282                                      eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
283         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
284                 return NT_STATUS_OK;
285         }
286         return status;
287 }
288
289 /*
290   save the set of DOS EAs
291 */
292 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
293                           struct xattr_DosEAs *eas)
294 {
295         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
296                 return NT_STATUS_OK;
297         }
298         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas, 
299                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
300 }
301
302
303 /*
304   load the set of streams from extended attributes
305 */
306 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
307                            struct xattr_DosStreams *streams)
308 {
309         NTSTATUS status;
310         ZERO_STRUCTP(streams);
311         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
312                 return NT_STATUS_OK;
313         }
314         status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd, 
315                                      XATTR_DOSSTREAMS_NAME,
316                                      streams, 
317                                      (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
318         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
319                 return NT_STATUS_OK;
320         }
321         return status;
322 }
323
324 /*
325   save the set of streams into filesystem xattr
326 */
327 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
328                            struct xattr_DosStreams *streams)
329 {
330         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
331                 return NT_STATUS_OK;
332         }
333         return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
334                                    XATTR_DOSSTREAMS_NAME, 
335                                    streams, 
336                                    (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
337 }
338
339
340 /*
341   load the current ACL from extended attributes
342 */
343 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
344                        struct xattr_NTACL *acl)
345 {
346         NTSTATUS status;
347         ZERO_STRUCTP(acl);
348         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
349                 return NT_STATUS_NOT_FOUND;
350         }
351         status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd, 
352                                      XATTR_NTACL_NAME,
353                                      acl, 
354                                      (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
355         return status;
356 }
357
358 /*
359   save the acl for a file into filesystem xattr
360 */
361 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
362                        struct xattr_NTACL *acl)
363 {
364         NTSTATUS status;
365         void *privs;
366
367         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
368                 return NT_STATUS_OK;
369         }
370
371         /* this xattr is in the "system" namespace, so we need
372            admin privileges to set it */
373         privs = root_privileges();
374         status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
375                                      XATTR_NTACL_NAME, 
376                                      acl, 
377                                      (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
378         talloc_free(privs);
379         return status;
380 }
381
382 /*
383   create a zero length xattr with the given name
384 */
385 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs, 
386                            const char *fname, int fd,
387                            const char *attr_prefix,
388                            const char *attr_name)
389 {
390         NTSTATUS status;
391         DATA_BLOB blob = data_blob(NULL, 0);
392         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
393         if (aname == NULL) {
394                 return NT_STATUS_NO_MEMORY;
395         }
396         status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
397         talloc_free(aname);
398         return status;
399 }
400
401
402 /*
403   delete a xattr with the given name
404 */
405 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs, 
406                            const char *fname, int fd,
407                            const char *attr_prefix,
408                            const char *attr_name)
409 {
410         NTSTATUS status;
411         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
412         if (aname == NULL) {
413                 return NT_STATUS_NO_MEMORY;
414         }
415         status = delete_xattr(pvfs, aname, fname, fd);
416         talloc_free(aname);
417         return status;
418 }
419
420 /*
421   load a xattr with the given name
422 */
423 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, 
424                          TALLOC_CTX *mem_ctx,
425                          const char *fname, int fd,
426                          const char *attr_prefix,
427                          const char *attr_name,
428                          size_t estimated_size,
429                          DATA_BLOB *blob)
430 {
431         NTSTATUS status;
432         char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
433         if (aname == NULL) {
434                 return NT_STATUS_NO_MEMORY;
435         }
436         status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
437         talloc_free(aname);
438         return status;
439 }
440
441 /*
442   save a xattr with the given name
443 */
444 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, 
445                          const char *fname, int fd,
446                          const char *attr_prefix,
447                          const char *attr_name,
448                          const DATA_BLOB *blob)
449 {
450         NTSTATUS status;
451         char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
452         if (aname == NULL) {
453                 return NT_STATUS_NO_MEMORY;
454         }
455         status = push_xattr_blob(pvfs, aname, fname, fd, blob);
456         talloc_free(aname);
457         return status;
458 }
459
460
461 /*
462   probe for system support for xattrs
463 */
464 void pvfs_xattr_probe(struct pvfs_state *pvfs)
465 {
466         TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
467         DATA_BLOB blob;
468         pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory, 
469                         -1, 1, &blob);
470         pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory, 
471                         -1, 1, &blob);
472         talloc_free(tmp_ctx);
473 }