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 "system/filesys.h"
25 #include "vfs_posix.h"
26 #include "librpc/gen_ndr/ndr_xattr.h"
29 pull a xattr as a blob, from either a file or a file descriptor
31 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
33 const char *attr_name,
36 size_t estimated_size,
39 #if HAVE_XATTR_SUPPORT
42 *blob = data_blob_talloc(mem_ctx, NULL, estimated_size);
43 if (blob->data == NULL) {
44 return NT_STATUS_NO_MEMORY;
49 ret = fgetxattr(fd, attr_name, blob->data, estimated_size);
51 ret = getxattr(fname, attr_name, blob->data, estimated_size);
53 if (ret == -1 && errno == ERANGE) {
55 blob->data = talloc_realloc(mem_ctx, blob->data, estimated_size);
56 if (blob->data == NULL) {
57 return NT_STATUS_NO_MEMORY;
59 blob->length = estimated_size;
65 return pvfs_map_errno(pvfs, errno);
72 return NT_STATUS_NOT_SUPPORTED;
77 push a xattr as a blob, from either a file or a file descriptor
79 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
80 const char *attr_name,
83 const DATA_BLOB *blob)
85 #if HAVE_XATTR_SUPPORT
89 ret = fsetxattr(fd, attr_name, blob->data, blob->length, 0);
91 ret = setxattr(fname, attr_name, blob->data, blob->length, 0);
94 return pvfs_map_errno(pvfs, errno);
99 return NT_STATUS_NOT_SUPPORTED;
107 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
108 const char *fname, int fd)
110 #if HAVE_XATTR_SUPPORT
114 ret = fremovexattr(fd, attr_name);
116 ret = removexattr(fname, attr_name);
119 return pvfs_map_errno(pvfs, errno);
124 return NT_STATUS_NOT_SUPPORTED;
129 load a NDR structure from a xattr
131 static NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
133 const char *fname, int fd, const char *attr_name,
134 void *p, ndr_pull_flags_fn_t pull_fn)
139 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
140 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
141 if (!NT_STATUS_IS_OK(status)) {
146 status = ndr_pull_struct_blob(&blob, mem_ctx, p, pull_fn);
148 data_blob_free(&blob);
154 save a NDR structure into a xattr
156 static NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
157 const char *fname, int fd, const char *attr_name,
158 void *p, ndr_push_flags_fn_t push_fn)
160 TALLOC_CTX *mem_ctx = talloc(NULL, 0);
164 status = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
165 if (!NT_STATUS_IS_OK(status)) {
166 talloc_free(mem_ctx);
170 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
171 talloc_free(mem_ctx);
178 fill in file attributes from extended attributes
180 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
183 struct xattr_DosAttrib attrib;
184 TALLOC_CTX *mem_ctx = talloc(name, 0);
185 struct xattr_DosInfo1 *info1;
187 if (name->stream_name != NULL) {
188 name->stream_exists = False;
190 name->stream_exists = True;
193 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
197 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
198 fd, XATTR_DOSATTRIB_NAME,
200 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
202 /* if the filesystem doesn't support them, then tell pvfs not to try again */
203 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
204 DEBUG(5,("pvfs_xattr: xattr not supported in filesystem\n"));
205 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
206 talloc_free(mem_ctx);
210 /* not having a DosAttrib is not an error */
211 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
212 talloc_free(mem_ctx);
216 if (!NT_STATUS_IS_OK(status)) {
217 talloc_free(mem_ctx);
221 switch (attrib.version) {
223 info1 = &attrib.info.info1;
224 name->dos.attrib = pvfs_attrib_normalise(info1->attrib);
225 name->dos.ea_size = info1->ea_size;
226 if (name->st.st_size == info1->size) {
227 name->dos.alloc_size =
228 pvfs_round_alloc_size(pvfs, info1->alloc_size);
230 if (info1->create_time != 0) {
231 name->dos.create_time = info1->create_time;
233 if (info1->change_time != 0) {
234 name->dos.change_time = info1->change_time;
239 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
240 attrib.version, name->full_name));
241 talloc_free(mem_ctx);
242 return NT_STATUS_INVALID_LEVEL;
244 talloc_free(mem_ctx);
246 status = pvfs_stream_info(pvfs, name, fd);
253 save the file attribute into the xattr
255 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
257 struct xattr_DosAttrib attrib;
258 struct xattr_DosInfo1 *info1;
260 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
265 info1 = &attrib.info.info1;
267 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib);
269 info1->attrib = name->dos.attrib;
270 info1->ea_size = name->dos.ea_size;
271 info1->size = name->st.st_size;
272 info1->alloc_size = name->dos.alloc_size;
273 info1->create_time = name->dos.create_time;
274 info1->change_time = name->dos.change_time;
276 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
277 XATTR_DOSATTRIB_NAME, &attrib,
278 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
283 load the set of DOS EAs
285 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
286 struct xattr_DosEAs *eas)
290 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
293 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
294 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
295 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
302 save the set of DOS EAs
304 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
305 struct xattr_DosEAs *eas)
307 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
310 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
311 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
316 load the set of streams from extended attributes
318 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
319 struct xattr_DosStreams *streams)
322 ZERO_STRUCTP(streams);
323 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
326 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
327 XATTR_DOSSTREAMS_NAME,
329 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
330 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
337 save the set of streams into filesystem xattr
339 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
340 struct xattr_DosStreams *streams)
342 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
345 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
346 XATTR_DOSSTREAMS_NAME,
348 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
353 load the current ACL from extended attributes
355 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
356 struct xattr_NTACL *acl)
360 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
363 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
366 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
371 save the acl for a file into filesystem xattr
373 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
374 struct xattr_NTACL *acl)
379 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
383 /* this xattr is in the "system" namespace, so we need
384 admin privileges to set it */
385 privs = root_privileges();
386 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
389 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
395 create a zero length xattr with the given name
397 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
398 const char *fname, int fd,
399 const char *attr_prefix,
400 const char *attr_name)
403 DATA_BLOB blob = data_blob(NULL, 0);
404 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
406 return NT_STATUS_NO_MEMORY;
408 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
415 delete a xattr with the given name
417 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
418 const char *fname, int fd,
419 const char *attr_prefix,
420 const char *attr_name)
423 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
425 return NT_STATUS_NO_MEMORY;
427 status = delete_xattr(pvfs, aname, fname, fd);
433 load a xattr with the given name
435 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
437 const char *fname, int fd,
438 const char *attr_prefix,
439 const char *attr_name,
440 size_t estimated_size,
444 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
446 return NT_STATUS_NO_MEMORY;
448 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
454 save a xattr with the given name
456 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
457 const char *fname, int fd,
458 const char *attr_prefix,
459 const char *attr_name,
460 const DATA_BLOB *blob)
463 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
465 return NT_STATUS_NO_MEMORY;
467 status = push_xattr_blob(pvfs, aname, fname, fd, blob);