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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "lib/util/unix_privs.h"
25 #include "librpc/gen_ndr/ndr_xattr.h"
26 #include "param/param.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 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)||
52 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) {
53 DEBUG(5,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status)));
54 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
55 status = NT_STATUS_NOT_FOUND;
62 push a xattr as a blob
64 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
65 const char *attr_name,
68 const DATA_BLOB *blob)
71 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
73 return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
80 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
81 const char *fname, int fd)
84 return delete_xattr_tdb(pvfs, attr_name, fname, fd);
86 return delete_xattr_system(pvfs, attr_name, fname, fd);
90 a hook called on unlink - allows the tdb xattr backend to cleanup
92 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
95 return unlink_xattr_tdb(pvfs, fname);
97 return unlink_xattr_system(pvfs, fname);
102 load a NDR structure from a xattr
104 NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
106 const char *fname, int fd, const char *attr_name,
107 void *p, void *pull_fn)
111 enum ndr_err_code ndr_err;
113 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
114 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
115 if (!NT_STATUS_IS_OK(status)) {
120 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx),
121 p, (ndr_pull_flags_fn_t)pull_fn);
122 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
123 return ndr_map_error2ntstatus(ndr_err);
126 data_blob_free(&blob);
132 save a NDR structure into a xattr
134 NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
135 const char *fname, int fd, const char *attr_name,
136 void *p, void *push_fn)
138 TALLOC_CTX *mem_ctx = talloc_new(NULL);
141 enum ndr_err_code ndr_err;
143 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, (ndr_push_flags_fn_t)push_fn);
144 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145 talloc_free(mem_ctx);
146 return ndr_map_error2ntstatus(ndr_err);
149 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
150 talloc_free(mem_ctx);
157 fill in file attributes from extended attributes
159 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
162 struct xattr_DosAttrib attrib;
163 TALLOC_CTX *mem_ctx = talloc_new(name);
164 struct xattr_DosInfo1 *info1;
165 struct xattr_DosInfo2 *info2;
167 if (name->stream_name != NULL) {
168 name->stream_exists = false;
170 name->stream_exists = true;
173 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
177 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
178 fd, XATTR_DOSATTRIB_NAME,
180 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
182 /* not having a DosAttrib is not an error */
183 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
184 talloc_free(mem_ctx);
185 return pvfs_stream_info(pvfs, name, fd);
188 if (!NT_STATUS_IS_OK(status)) {
189 talloc_free(mem_ctx);
193 switch (attrib.version) {
195 info1 = &attrib.info.info1;
196 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
198 name->dos.ea_size = info1->ea_size;
199 if (name->st.st_size == info1->size) {
200 name->dos.alloc_size =
201 pvfs_round_alloc_size(pvfs, info1->alloc_size);
203 if (!null_nttime(info1->create_time)) {
204 name->dos.create_time = info1->create_time;
206 if (!null_nttime(info1->change_time)) {
207 name->dos.change_time = info1->change_time;
213 info2 = &attrib.info.info2;
214 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
216 name->dos.ea_size = info2->ea_size;
217 if (name->st.st_size == info2->size) {
218 name->dos.alloc_size =
219 pvfs_round_alloc_size(pvfs, info2->alloc_size);
221 if (!null_nttime(info2->create_time)) {
222 name->dos.create_time = info2->create_time;
224 if (!null_nttime(info2->change_time)) {
225 name->dos.change_time = info2->change_time;
227 name->dos.flags = info2->flags;
228 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
229 name->dos.write_time = info2->write_time;
234 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
235 attrib.version, name->full_name));
236 talloc_free(mem_ctx);
237 return NT_STATUS_INVALID_LEVEL;
239 talloc_free(mem_ctx);
241 status = pvfs_stream_info(pvfs, name, fd);
248 save the file attribute into the xattr
250 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
252 struct xattr_DosAttrib attrib;
253 struct xattr_DosInfo2 *info2;
255 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
260 info2 = &attrib.info.info2;
262 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
264 info2->attrib = name->dos.attrib;
265 info2->ea_size = name->dos.ea_size;
266 info2->size = name->st.st_size;
267 info2->alloc_size = name->dos.alloc_size;
268 info2->create_time = name->dos.create_time;
269 info2->change_time = name->dos.change_time;
270 info2->write_time = name->dos.write_time;
271 info2->flags = name->dos.flags;
274 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
275 XATTR_DOSATTRIB_NAME, &attrib,
276 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
281 load the set of DOS EAs
283 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
284 struct xattr_DosEAs *eas)
288 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
291 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
292 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
293 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
300 save the set of DOS EAs
302 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
303 struct xattr_DosEAs *eas)
305 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
308 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
309 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
314 load the set of streams from extended attributes
316 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
317 struct xattr_DosStreams *streams)
320 ZERO_STRUCTP(streams);
321 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
324 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
325 XATTR_DOSSTREAMS_NAME,
327 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
328 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335 save the set of streams into filesystem xattr
337 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
338 struct xattr_DosStreams *streams)
340 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
343 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
344 XATTR_DOSSTREAMS_NAME,
346 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
351 load the current ACL from extended attributes
353 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
354 struct xattr_NTACL *acl)
358 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
359 return NT_STATUS_NOT_FOUND;
361 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
364 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
369 save the acl for a file into filesystem xattr
371 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
372 struct xattr_NTACL *acl)
377 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
381 /* this xattr is in the "system" namespace, so we need
382 admin privileges to set it */
383 privs = root_privileges();
384 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
387 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
393 create a zero length xattr with the given name
395 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
396 const char *fname, int fd,
397 const char *attr_prefix,
398 const char *attr_name)
401 DATA_BLOB blob = data_blob(NULL, 0);
402 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
404 return NT_STATUS_NO_MEMORY;
406 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
413 delete a xattr with the given name
415 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
416 const char *fname, int fd,
417 const char *attr_prefix,
418 const char *attr_name)
421 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
423 return NT_STATUS_NO_MEMORY;
425 status = delete_xattr(pvfs, aname, fname, fd);
431 load a xattr with the given name
433 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
435 const char *fname, int fd,
436 const char *attr_prefix,
437 const char *attr_name,
438 size_t estimated_size,
442 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
444 return NT_STATUS_NO_MEMORY;
446 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
452 save a xattr with the given name
454 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
455 const char *fname, int fd,
456 const char *attr_prefix,
457 const char *attr_name,
458 const DATA_BLOB *blob)
461 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
463 return NT_STATUS_NO_MEMORY;
465 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
472 probe for system support for xattrs
474 void pvfs_xattr_probe(struct pvfs_state *pvfs)
476 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
478 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
480 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
482 talloc_free(tmp_ctx);