2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - xattr support
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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.
24 #include "vfs_posix.h"
25 #include "util/unix_privs.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
29 pull a xattr as a blob
31 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
33 const char *attr_name,
36 size_t estimated_size,
42 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname,
43 fd, estimated_size, blob);
46 status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname,
47 fd, estimated_size, blob);
49 /* if the filesystem doesn't support them, then tell pvfs not to try again */
50 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
51 DEBUG(5,("pvfs_xattr: xattr not supported in filesystem\n"));
52 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
53 status = NT_STATUS_NOT_FOUND;
60 push a xattr as a blob
62 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
63 const char *attr_name,
66 const DATA_BLOB *blob)
69 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
71 return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
78 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
79 const char *fname, int fd)
82 return delete_xattr_tdb(pvfs, attr_name, fname, fd);
84 return delete_xattr_system(pvfs, attr_name, fname, fd);
88 a hook called on unlink - allows the tdb xattr backend to cleanup
90 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
93 return unlink_xattr_tdb(pvfs, fname);
95 return unlink_xattr_system(pvfs, fname);
100 load a NDR structure from a xattr
102 static NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
104 const char *fname, int fd, const char *attr_name,
105 void *p, ndr_pull_flags_fn_t pull_fn)
110 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
111 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
112 if (!NT_STATUS_IS_OK(status)) {
117 status = ndr_pull_struct_blob(&blob, mem_ctx, p, pull_fn);
119 data_blob_free(&blob);
125 save a NDR structure into a xattr
127 static NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
128 const char *fname, int fd, const char *attr_name,
129 void *p, ndr_push_flags_fn_t push_fn)
131 TALLOC_CTX *mem_ctx = talloc_new(NULL);
135 status = ndr_push_struct_blob(&blob, mem_ctx, p, push_fn);
136 if (!NT_STATUS_IS_OK(status)) {
137 talloc_free(mem_ctx);
141 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
142 talloc_free(mem_ctx);
149 fill in file attributes from extended attributes
151 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
154 struct xattr_DosAttrib attrib;
155 TALLOC_CTX *mem_ctx = talloc_new(name);
156 struct xattr_DosInfo1 *info1;
157 struct xattr_DosInfo2 *info2;
159 if (name->stream_name != NULL) {
160 name->stream_exists = False;
162 name->stream_exists = True;
165 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
169 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
170 fd, XATTR_DOSATTRIB_NAME,
172 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
174 /* not having a DosAttrib is not an error */
175 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
176 talloc_free(mem_ctx);
177 return pvfs_stream_info(pvfs, name, fd);
180 if (!NT_STATUS_IS_OK(status)) {
181 talloc_free(mem_ctx);
185 switch (attrib.version) {
187 info1 = &attrib.info.info1;
188 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
190 name->dos.ea_size = info1->ea_size;
191 if (name->st.st_size == info1->size) {
192 name->dos.alloc_size =
193 pvfs_round_alloc_size(pvfs, info1->alloc_size);
195 if (!null_nttime(info1->create_time)) {
196 name->dos.create_time = info1->create_time;
198 if (!null_nttime(info1->change_time)) {
199 name->dos.change_time = info1->change_time;
205 info2 = &attrib.info.info2;
206 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
208 name->dos.ea_size = info2->ea_size;
209 if (name->st.st_size == info2->size) {
210 name->dos.alloc_size =
211 pvfs_round_alloc_size(pvfs, info2->alloc_size);
213 if (!null_nttime(info2->create_time)) {
214 name->dos.create_time = info2->create_time;
216 if (!null_nttime(info2->change_time)) {
217 name->dos.change_time = info2->change_time;
219 name->dos.flags = info2->flags;
220 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
221 name->dos.write_time = info2->write_time;
226 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
227 attrib.version, name->full_name));
228 talloc_free(mem_ctx);
229 return NT_STATUS_INVALID_LEVEL;
231 talloc_free(mem_ctx);
233 status = pvfs_stream_info(pvfs, name, fd);
240 save the file attribute into the xattr
242 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
244 struct xattr_DosAttrib attrib;
245 struct xattr_DosInfo2 *info2;
247 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
252 info2 = &attrib.info.info2;
254 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
256 info2->attrib = name->dos.attrib;
257 info2->ea_size = name->dos.ea_size;
258 info2->size = name->st.st_size;
259 info2->alloc_size = name->dos.alloc_size;
260 info2->create_time = name->dos.create_time;
261 info2->change_time = name->dos.change_time;
262 info2->write_time = name->dos.write_time;
263 info2->flags = name->dos.flags;
266 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
267 XATTR_DOSATTRIB_NAME, &attrib,
268 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
273 load the set of DOS EAs
275 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
276 struct xattr_DosEAs *eas)
280 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
283 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
284 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
285 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
292 save the set of DOS EAs
294 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
295 struct xattr_DosEAs *eas)
297 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
300 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
301 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
306 load the set of streams from extended attributes
308 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
309 struct xattr_DosStreams *streams)
312 ZERO_STRUCTP(streams);
313 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
316 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
317 XATTR_DOSSTREAMS_NAME,
319 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
320 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
327 save the set of streams into filesystem xattr
329 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
330 struct xattr_DosStreams *streams)
332 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
335 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
336 XATTR_DOSSTREAMS_NAME,
338 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
343 load the current ACL from extended attributes
345 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
346 struct xattr_NTACL *acl)
350 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
351 return NT_STATUS_NOT_FOUND;
353 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
356 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
361 save the acl for a file into filesystem xattr
363 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
364 struct xattr_NTACL *acl)
369 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
373 /* this xattr is in the "system" namespace, so we need
374 admin privileges to set it */
375 privs = root_privileges();
376 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
379 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
385 create a zero length xattr with the given name
387 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
388 const char *fname, int fd,
389 const char *attr_prefix,
390 const char *attr_name)
393 DATA_BLOB blob = data_blob(NULL, 0);
394 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
396 return NT_STATUS_NO_MEMORY;
398 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
405 delete a xattr with the given name
407 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
408 const char *fname, int fd,
409 const char *attr_prefix,
410 const char *attr_name)
413 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
415 return NT_STATUS_NO_MEMORY;
417 status = delete_xattr(pvfs, aname, fname, fd);
423 load a xattr with the given name
425 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
427 const char *fname, int fd,
428 const char *attr_prefix,
429 const char *attr_name,
430 size_t estimated_size,
434 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
436 return NT_STATUS_NO_MEMORY;
438 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
444 save a xattr with the given name
446 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
447 const char *fname, int fd,
448 const char *attr_prefix,
449 const char *attr_name,
450 const DATA_BLOB *blob)
453 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
455 return NT_STATUS_NO_MEMORY;
457 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
464 probe for system support for xattrs
466 void pvfs_xattr_probe(struct pvfs_state *pvfs)
468 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
470 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
472 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
474 talloc_free(tmp_ctx);