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"
27 #include "ntvfs/posix/posix_eadb_proto.h"
30 pull a xattr as a blob
32 static NTSTATUS
pull_xattr_blob(struct pvfs_state
*pvfs
,
34 const char *attr_name
,
37 size_t estimated_size
,
43 return pull_xattr_blob_tdb(pvfs
, mem_ctx
, attr_name
, fname
,
44 fd
, estimated_size
, blob
);
47 status
= pull_xattr_blob_system(pvfs
, mem_ctx
, attr_name
, fname
,
48 fd
, estimated_size
, blob
);
50 /* if the filesystem doesn't support them, then tell pvfs not to try again */
51 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)||
52 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)||
53 NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_SYSTEM_SERVICE
)) {
54 DEBUG(2,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status
)));
55 pvfs
->flags
&= ~PVFS_FLAG_XATTR_ENABLE
;
56 status
= NT_STATUS_NOT_FOUND
;
63 push a xattr as a blob
65 static NTSTATUS
push_xattr_blob(struct pvfs_state
*pvfs
,
66 const char *attr_name
,
69 const DATA_BLOB
*blob
)
72 return push_xattr_blob_tdb(pvfs
, attr_name
, fname
, fd
, blob
);
74 return push_xattr_blob_system(pvfs
, attr_name
, fname
, fd
, blob
);
81 static NTSTATUS
delete_xattr(struct pvfs_state
*pvfs
, const char *attr_name
,
82 const char *fname
, int fd
)
85 return delete_posix_eadb(pvfs
, attr_name
, fname
, fd
);
87 return delete_xattr_system(pvfs
, attr_name
, fname
, fd
);
91 a hook called on unlink - allows the tdb xattr backend to cleanup
93 NTSTATUS
pvfs_xattr_unlink_hook(struct pvfs_state
*pvfs
, const char *fname
)
96 return unlink_posix_eadb(pvfs
, fname
);
98 return unlink_xattr_system(pvfs
, fname
);
103 load a NDR structure from a xattr
105 NTSTATUS
pvfs_xattr_ndr_load(struct pvfs_state
*pvfs
,
107 const char *fname
, int fd
, const char *attr_name
,
108 void *p
, void *pull_fn
)
112 enum ndr_err_code ndr_err
;
114 status
= pull_xattr_blob(pvfs
, mem_ctx
, attr_name
, fname
,
115 fd
, XATTR_DOSATTRIB_ESTIMATED_SIZE
, &blob
);
116 if (!NT_STATUS_IS_OK(status
)) {
121 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, p
,
122 (ndr_pull_flags_fn_t
)pull_fn
);
123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
124 return ndr_map_error2ntstatus(ndr_err
);
127 data_blob_free(&blob
);
133 save a NDR structure into a xattr
135 NTSTATUS
pvfs_xattr_ndr_save(struct pvfs_state
*pvfs
,
136 const char *fname
, int fd
, const char *attr_name
,
137 void *p
, void *push_fn
)
139 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
142 enum ndr_err_code ndr_err
;
144 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, p
, (ndr_push_flags_fn_t
)push_fn
);
145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
146 talloc_free(mem_ctx
);
147 return ndr_map_error2ntstatus(ndr_err
);
150 status
= push_xattr_blob(pvfs
, attr_name
, fname
, fd
, &blob
);
151 talloc_free(mem_ctx
);
158 fill in file attributes from extended attributes
160 NTSTATUS
pvfs_dosattrib_load(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
)
163 struct xattr_DosAttrib attrib
;
164 TALLOC_CTX
*mem_ctx
= talloc_new(name
);
165 struct xattr_DosInfo1
*info1
;
166 struct xattr_DosInfo2Old
*info2
;
168 if (name
->stream_name
!= NULL
) {
169 name
->stream_exists
= false;
171 name
->stream_exists
= true;
174 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
178 status
= pvfs_xattr_ndr_load(pvfs
, mem_ctx
, name
->full_name
,
179 fd
, XATTR_DOSATTRIB_NAME
,
181 (void *) ndr_pull_xattr_DosAttrib
);
183 /* not having a DosAttrib is not an error */
184 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
185 talloc_free(mem_ctx
);
186 return pvfs_stream_info(pvfs
, name
, fd
);
189 if (!NT_STATUS_IS_OK(status
)) {
190 talloc_free(mem_ctx
);
194 switch (attrib
.version
) {
196 info1
= &attrib
.info
.info1
;
197 name
->dos
.attrib
= pvfs_attrib_normalise(info1
->attrib
,
199 name
->dos
.ea_size
= info1
->ea_size
;
200 if (name
->st
.st_size
== info1
->size
) {
201 name
->dos
.alloc_size
=
202 pvfs_round_alloc_size(pvfs
, info1
->alloc_size
);
204 if (!null_nttime(info1
->create_time
)) {
205 name
->dos
.create_time
= info1
->create_time
;
207 if (!null_nttime(info1
->change_time
)) {
208 name
->dos
.change_time
= info1
->change_time
;
215 * Note: This is only used to parse existing values from disk
216 * We use xattr_DosInfo1 again for storing new values
218 info2
= &attrib
.info
.oldinfo2
;
219 name
->dos
.attrib
= pvfs_attrib_normalise(info2
->attrib
,
221 name
->dos
.ea_size
= info2
->ea_size
;
222 if (name
->st
.st_size
== info2
->size
) {
223 name
->dos
.alloc_size
=
224 pvfs_round_alloc_size(pvfs
, info2
->alloc_size
);
226 if (!null_nttime(info2
->create_time
)) {
227 name
->dos
.create_time
= info2
->create_time
;
229 if (!null_nttime(info2
->change_time
)) {
230 name
->dos
.change_time
= info2
->change_time
;
232 name
->dos
.flags
= info2
->flags
;
236 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
237 attrib
.version
, name
->full_name
));
238 talloc_free(mem_ctx
);
239 return NT_STATUS_INVALID_LEVEL
;
241 talloc_free(mem_ctx
);
243 status
= pvfs_stream_info(pvfs
, name
, fd
);
250 save the file attribute into the xattr
252 NTSTATUS
pvfs_dosattrib_save(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
)
254 struct xattr_DosAttrib attrib
;
255 struct xattr_DosInfo1
*info1
;
257 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
262 info1
= &attrib
.info
.info1
;
264 name
->dos
.attrib
= pvfs_attrib_normalise(name
->dos
.attrib
, name
->st
.st_mode
);
266 info1
->attrib
= name
->dos
.attrib
;
267 info1
->ea_size
= name
->dos
.ea_size
;
268 info1
->size
= name
->st
.st_size
;
269 info1
->alloc_size
= name
->dos
.alloc_size
;
270 info1
->create_time
= name
->dos
.create_time
;
271 info1
->change_time
= name
->dos
.change_time
;
273 return pvfs_xattr_ndr_save(pvfs
, name
->full_name
, fd
,
274 XATTR_DOSATTRIB_NAME
, &attrib
,
275 (void *) ndr_push_xattr_DosAttrib
);
280 load the set of DOS EAs
282 NTSTATUS
pvfs_doseas_load(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
283 struct xattr_DosEAs
*eas
)
288 if (name
->stream_name
) {
289 /* We don't support EAs on streams */
290 return NT_STATUS_INVALID_PARAMETER
;
293 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
296 status
= pvfs_xattr_ndr_load(pvfs
, eas
, name
->full_name
, fd
, XATTR_DOSEAS_NAME
,
297 eas
, (void *) ndr_pull_xattr_DosEAs
);
298 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
305 save the set of DOS EAs
307 NTSTATUS
pvfs_doseas_save(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
308 struct xattr_DosEAs
*eas
)
310 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
313 return pvfs_xattr_ndr_save(pvfs
, name
->full_name
, fd
, XATTR_DOSEAS_NAME
, eas
,
314 (void *) ndr_push_xattr_DosEAs
);
319 load the set of streams from extended attributes
321 NTSTATUS
pvfs_streams_load(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
322 struct xattr_DosStreams
*streams
)
325 ZERO_STRUCTP(streams
);
326 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
329 status
= pvfs_xattr_ndr_load(pvfs
, streams
, name
->full_name
, fd
,
330 XATTR_DOSSTREAMS_NAME
,
332 (void *) ndr_pull_xattr_DosStreams
);
333 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
340 save the set of streams into filesystem xattr
342 NTSTATUS
pvfs_streams_save(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
343 struct xattr_DosStreams
*streams
)
345 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
348 return pvfs_xattr_ndr_save(pvfs
, name
->full_name
, fd
,
349 XATTR_DOSSTREAMS_NAME
,
351 (void *) ndr_push_xattr_DosStreams
);
356 load the current ACL from extended attributes
358 NTSTATUS
pvfs_acl_load(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
359 struct xattr_NTACL
*acl
)
363 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
364 return NT_STATUS_NOT_FOUND
;
366 status
= pvfs_xattr_ndr_load(pvfs
, acl
, name
->full_name
, fd
,
369 (void *) ndr_pull_xattr_NTACL
);
374 save the acl for a file into filesystem xattr
376 NTSTATUS
pvfs_acl_save(struct pvfs_state
*pvfs
, struct pvfs_filename
*name
, int fd
,
377 struct xattr_NTACL
*acl
)
382 if (!(pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
)) {
386 /* this xattr is in the "system" namespace, so we need
387 admin privileges to set it */
388 privs
= root_privileges();
389 status
= pvfs_xattr_ndr_save(pvfs
, name
->full_name
, fd
,
392 (void *) ndr_push_xattr_NTACL
);
398 create a zero length xattr with the given name
400 NTSTATUS
pvfs_xattr_create(struct pvfs_state
*pvfs
,
401 const char *fname
, int fd
,
402 const char *attr_prefix
,
403 const char *attr_name
)
406 DATA_BLOB blob
= data_blob(NULL
, 0);
407 char *aname
= talloc_asprintf(NULL
, "%s%s", attr_prefix
, attr_name
);
409 return NT_STATUS_NO_MEMORY
;
411 status
= push_xattr_blob(pvfs
, aname
, fname
, fd
, &blob
);
418 delete a xattr with the given name
420 NTSTATUS
pvfs_xattr_delete(struct pvfs_state
*pvfs
,
421 const char *fname
, int fd
,
422 const char *attr_prefix
,
423 const char *attr_name
)
426 char *aname
= talloc_asprintf(NULL
, "%s%s", attr_prefix
, attr_name
);
428 return NT_STATUS_NO_MEMORY
;
430 status
= delete_xattr(pvfs
, aname
, fname
, fd
);
436 load a xattr with the given name
438 NTSTATUS
pvfs_xattr_load(struct pvfs_state
*pvfs
,
440 const char *fname
, int fd
,
441 const char *attr_prefix
,
442 const char *attr_name
,
443 size_t estimated_size
,
447 char *aname
= talloc_asprintf(mem_ctx
, "%s%s", attr_prefix
, attr_name
);
449 return NT_STATUS_NO_MEMORY
;
451 status
= pull_xattr_blob(pvfs
, mem_ctx
, aname
, fname
, fd
, estimated_size
, blob
);
457 save a xattr with the given name
459 NTSTATUS
pvfs_xattr_save(struct pvfs_state
*pvfs
,
460 const char *fname
, int fd
,
461 const char *attr_prefix
,
462 const char *attr_name
,
463 const DATA_BLOB
*blob
)
466 char *aname
= talloc_asprintf(NULL
, "%s%s", attr_prefix
, attr_name
);
468 return NT_STATUS_NO_MEMORY
;
470 status
= push_xattr_blob(pvfs
, aname
, fname
, fd
, blob
);
477 probe for system support for xattrs
479 void pvfs_xattr_probe(struct pvfs_state
*pvfs
)
481 TALLOC_CTX
*tmp_ctx
= talloc_new(pvfs
);
483 pull_xattr_blob(pvfs
, tmp_ctx
, "user.XattrProbe", pvfs
->base_directory
,
485 pull_xattr_blob(pvfs
, tmp_ctx
, "security.XattrProbe", pvfs
->base_directory
,
487 talloc_free(tmp_ctx
);