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"
28 pull a xattr as a blob
30 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
32 const char *attr_name,
35 size_t estimated_size,
41 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname,
42 fd, estimated_size, blob);
45 status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname,
46 fd, estimated_size, blob);
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 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)||
51 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) {
52 DEBUG(5,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status)));
53 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
54 status = NT_STATUS_NOT_FOUND;
61 push a xattr as a blob
63 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
64 const char *attr_name,
67 const DATA_BLOB *blob)
70 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob);
72 return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob);
79 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name,
80 const char *fname, int fd)
83 return delete_xattr_tdb(pvfs, attr_name, fname, fd);
85 return delete_xattr_system(pvfs, attr_name, fname, fd);
89 a hook called on unlink - allows the tdb xattr backend to cleanup
91 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
94 return unlink_xattr_tdb(pvfs, fname);
96 return unlink_xattr_system(pvfs, fname);
101 load a NDR structure from a xattr
103 _PUBLIC_ NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
105 const char *fname, int fd, const char *attr_name,
106 void *p, void *pull_fn)
111 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
112 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
113 if (!NT_STATUS_IS_OK(status)) {
118 status = ndr_pull_struct_blob(&blob, mem_ctx, p, (ndr_pull_flags_fn_t)pull_fn);
120 data_blob_free(&blob);
126 save a NDR structure into a xattr
128 _PUBLIC_ NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
129 const char *fname, int fd, const char *attr_name,
130 void *p, void *push_fn)
132 TALLOC_CTX *mem_ctx = talloc_new(NULL);
136 status = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
137 if (!NT_STATUS_IS_OK(status)) {
138 talloc_free(mem_ctx);
142 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
143 talloc_free(mem_ctx);
150 fill in file attributes from extended attributes
152 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
155 struct xattr_DosAttrib attrib;
156 TALLOC_CTX *mem_ctx = talloc_new(name);
157 struct xattr_DosInfo1 *info1;
158 struct xattr_DosInfo2 *info2;
160 if (name->stream_name != NULL) {
161 name->stream_exists = False;
163 name->stream_exists = True;
166 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
170 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
171 fd, XATTR_DOSATTRIB_NAME,
173 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
175 /* not having a DosAttrib is not an error */
176 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
177 talloc_free(mem_ctx);
178 return pvfs_stream_info(pvfs, name, fd);
181 if (!NT_STATUS_IS_OK(status)) {
182 talloc_free(mem_ctx);
186 switch (attrib.version) {
188 info1 = &attrib.info.info1;
189 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
191 name->dos.ea_size = info1->ea_size;
192 if (name->st.st_size == info1->size) {
193 name->dos.alloc_size =
194 pvfs_round_alloc_size(pvfs, info1->alloc_size);
196 if (!null_nttime(info1->create_time)) {
197 name->dos.create_time = info1->create_time;
199 if (!null_nttime(info1->change_time)) {
200 name->dos.change_time = info1->change_time;
206 info2 = &attrib.info.info2;
207 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
209 name->dos.ea_size = info2->ea_size;
210 if (name->st.st_size == info2->size) {
211 name->dos.alloc_size =
212 pvfs_round_alloc_size(pvfs, info2->alloc_size);
214 if (!null_nttime(info2->create_time)) {
215 name->dos.create_time = info2->create_time;
217 if (!null_nttime(info2->change_time)) {
218 name->dos.change_time = info2->change_time;
220 name->dos.flags = info2->flags;
221 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
222 name->dos.write_time = info2->write_time;
227 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
228 attrib.version, name->full_name));
229 talloc_free(mem_ctx);
230 return NT_STATUS_INVALID_LEVEL;
232 talloc_free(mem_ctx);
234 status = pvfs_stream_info(pvfs, name, fd);
241 save the file attribute into the xattr
243 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
245 struct xattr_DosAttrib attrib;
246 struct xattr_DosInfo2 *info2;
248 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
253 info2 = &attrib.info.info2;
255 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
257 info2->attrib = name->dos.attrib;
258 info2->ea_size = name->dos.ea_size;
259 info2->size = name->st.st_size;
260 info2->alloc_size = name->dos.alloc_size;
261 info2->create_time = name->dos.create_time;
262 info2->change_time = name->dos.change_time;
263 info2->write_time = name->dos.write_time;
264 info2->flags = name->dos.flags;
267 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
268 XATTR_DOSATTRIB_NAME, &attrib,
269 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
274 load the set of DOS EAs
276 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
277 struct xattr_DosEAs *eas)
281 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
284 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
285 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
286 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
293 save the set of DOS EAs
295 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
296 struct xattr_DosEAs *eas)
298 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
301 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
302 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
307 load the set of streams from extended attributes
309 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
310 struct xattr_DosStreams *streams)
313 ZERO_STRUCTP(streams);
314 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
317 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
318 XATTR_DOSSTREAMS_NAME,
320 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
321 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
328 save the set of streams into filesystem xattr
330 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
331 struct xattr_DosStreams *streams)
333 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
336 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
337 XATTR_DOSSTREAMS_NAME,
339 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
344 load the current ACL from extended attributes
346 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
347 struct xattr_NTACL *acl)
351 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
352 return NT_STATUS_NOT_FOUND;
354 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
357 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
362 save the acl for a file into filesystem xattr
364 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
365 struct xattr_NTACL *acl)
370 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
374 /* this xattr is in the "system" namespace, so we need
375 admin privileges to set it */
376 privs = root_privileges();
377 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
380 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
386 create a zero length xattr with the given name
388 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
389 const char *fname, int fd,
390 const char *attr_prefix,
391 const char *attr_name)
394 DATA_BLOB blob = data_blob(NULL, 0);
395 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
397 return NT_STATUS_NO_MEMORY;
399 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
406 delete a xattr with the given name
408 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
409 const char *fname, int fd,
410 const char *attr_prefix,
411 const char *attr_name)
414 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
416 return NT_STATUS_NO_MEMORY;
418 status = delete_xattr(pvfs, aname, fname, fd);
424 load a xattr with the given name
426 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
428 const char *fname, int fd,
429 const char *attr_prefix,
430 const char *attr_name,
431 size_t estimated_size,
435 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
437 return NT_STATUS_NO_MEMORY;
439 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
445 save a xattr with the given name
447 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
448 const char *fname, int fd,
449 const char *attr_prefix,
450 const char *attr_name,
451 const DATA_BLOB *blob)
454 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
456 return NT_STATUS_NO_MEMORY;
458 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
465 probe for system support for xattrs
467 void pvfs_xattr_probe(struct pvfs_state *pvfs)
469 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
471 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
473 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
475 talloc_free(tmp_ctx);