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 "lib/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 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 _PUBLIC_ 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)
112 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname,
113 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
114 if (!NT_STATUS_IS_OK(status)) {
119 status = ndr_pull_struct_blob(&blob, mem_ctx, p, (ndr_pull_flags_fn_t)pull_fn);
121 data_blob_free(&blob);
127 save a NDR structure into a xattr
129 _PUBLIC_ NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
130 const char *fname, int fd, const char *attr_name,
131 void *p, void *push_fn)
133 TALLOC_CTX *mem_ctx = talloc_new(NULL);
137 status = ndr_push_struct_blob(&blob, mem_ctx, p, (ndr_push_flags_fn_t)push_fn);
138 if (!NT_STATUS_IS_OK(status)) {
139 talloc_free(mem_ctx);
143 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob);
144 talloc_free(mem_ctx);
151 fill in file attributes from extended attributes
153 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
156 struct xattr_DosAttrib attrib;
157 TALLOC_CTX *mem_ctx = talloc_new(name);
158 struct xattr_DosInfo1 *info1;
159 struct xattr_DosInfo2 *info2;
161 if (name->stream_name != NULL) {
162 name->stream_exists = False;
164 name->stream_exists = True;
167 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
171 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name,
172 fd, XATTR_DOSATTRIB_NAME,
174 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
176 /* not having a DosAttrib is not an error */
177 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
178 talloc_free(mem_ctx);
179 return pvfs_stream_info(pvfs, name, fd);
182 if (!NT_STATUS_IS_OK(status)) {
183 talloc_free(mem_ctx);
187 switch (attrib.version) {
189 info1 = &attrib.info.info1;
190 name->dos.attrib = pvfs_attrib_normalise(info1->attrib,
192 name->dos.ea_size = info1->ea_size;
193 if (name->st.st_size == info1->size) {
194 name->dos.alloc_size =
195 pvfs_round_alloc_size(pvfs, info1->alloc_size);
197 if (!null_nttime(info1->create_time)) {
198 name->dos.create_time = info1->create_time;
200 if (!null_nttime(info1->change_time)) {
201 name->dos.change_time = info1->change_time;
207 info2 = &attrib.info.info2;
208 name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
210 name->dos.ea_size = info2->ea_size;
211 if (name->st.st_size == info2->size) {
212 name->dos.alloc_size =
213 pvfs_round_alloc_size(pvfs, info2->alloc_size);
215 if (!null_nttime(info2->create_time)) {
216 name->dos.create_time = info2->create_time;
218 if (!null_nttime(info2->change_time)) {
219 name->dos.change_time = info2->change_time;
221 name->dos.flags = info2->flags;
222 if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
223 name->dos.write_time = info2->write_time;
228 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
229 attrib.version, name->full_name));
230 talloc_free(mem_ctx);
231 return NT_STATUS_INVALID_LEVEL;
233 talloc_free(mem_ctx);
235 status = pvfs_stream_info(pvfs, name, fd);
242 save the file attribute into the xattr
244 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
246 struct xattr_DosAttrib attrib;
247 struct xattr_DosInfo2 *info2;
249 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
254 info2 = &attrib.info.info2;
256 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
258 info2->attrib = name->dos.attrib;
259 info2->ea_size = name->dos.ea_size;
260 info2->size = name->st.st_size;
261 info2->alloc_size = name->dos.alloc_size;
262 info2->create_time = name->dos.create_time;
263 info2->change_time = name->dos.change_time;
264 info2->write_time = name->dos.write_time;
265 info2->flags = name->dos.flags;
268 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
269 XATTR_DOSATTRIB_NAME, &attrib,
270 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
275 load the set of DOS EAs
277 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
278 struct xattr_DosEAs *eas)
282 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
285 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
286 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
287 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
294 save the set of DOS EAs
296 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
297 struct xattr_DosEAs *eas)
299 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
302 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
303 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
308 load the set of streams from extended attributes
310 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
311 struct xattr_DosStreams *streams)
314 ZERO_STRUCTP(streams);
315 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
318 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
319 XATTR_DOSSTREAMS_NAME,
321 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
322 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
329 save the set of streams into filesystem xattr
331 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
332 struct xattr_DosStreams *streams)
334 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
337 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
338 XATTR_DOSSTREAMS_NAME,
340 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
345 load the current ACL from extended attributes
347 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
348 struct xattr_NTACL *acl)
352 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
353 return NT_STATUS_NOT_FOUND;
355 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
358 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
363 save the acl for a file into filesystem xattr
365 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
366 struct xattr_NTACL *acl)
371 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
375 /* this xattr is in the "system" namespace, so we need
376 admin privileges to set it */
377 privs = root_privileges();
378 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
381 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
387 create a zero length xattr with the given name
389 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
390 const char *fname, int fd,
391 const char *attr_prefix,
392 const char *attr_name)
395 DATA_BLOB blob = data_blob(NULL, 0);
396 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
398 return NT_STATUS_NO_MEMORY;
400 status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
407 delete a xattr with the given name
409 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
410 const char *fname, int fd,
411 const char *attr_prefix,
412 const char *attr_name)
415 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
417 return NT_STATUS_NO_MEMORY;
419 status = delete_xattr(pvfs, aname, fname, fd);
425 load a xattr with the given name
427 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
429 const char *fname, int fd,
430 const char *attr_prefix,
431 const char *attr_name,
432 size_t estimated_size,
436 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
438 return NT_STATUS_NO_MEMORY;
440 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
446 save a xattr with the given name
448 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
449 const char *fname, int fd,
450 const char *attr_prefix,
451 const char *attr_name,
452 const DATA_BLOB *blob)
455 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
457 return NT_STATUS_NO_MEMORY;
459 status = push_xattr_blob(pvfs, aname, fname, fd, blob);
466 probe for system support for xattrs
468 void pvfs_xattr_probe(struct pvfs_state *pvfs)
470 TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
472 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
474 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
476 talloc_free(tmp_ctx);