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