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(2,("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_DosInfo2Old *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;
214
* Note: This is only used to parse existing values from disk
215
* We use xattr_DosInfo1 again for storing new values
217
info2 = &attrib.info.oldinfo2;
218
name->dos.attrib = pvfs_attrib_normalise(info2->attrib,
220
name->dos.ea_size = info2->ea_size;
221
if (name->st.st_size == info2->size) {
222
name->dos.alloc_size =
223
pvfs_round_alloc_size(pvfs, info2->alloc_size);
225
if (!null_nttime(info2->create_time)) {
226
name->dos.create_time = info2->create_time;
228
if (!null_nttime(info2->change_time)) {
229
name->dos.change_time = info2->change_time;
231
name->dos.flags = info2->flags;
235
DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
236
attrib.version, name->full_name));
237
talloc_free(mem_ctx);
238
return NT_STATUS_INVALID_LEVEL;
240
talloc_free(mem_ctx);
242
status = pvfs_stream_info(pvfs, name, fd);
249
save the file attribute into the xattr
251
NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
253
struct xattr_DosAttrib attrib;
254
struct xattr_DosInfo1 *info1;
256
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
261
info1 = &attrib.info.info1;
263
name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode);
265
info1->attrib = name->dos.attrib;
266
info1->ea_size = name->dos.ea_size;
267
info1->size = name->st.st_size;
268
info1->alloc_size = name->dos.alloc_size;
269
info1->create_time = name->dos.create_time;
270
info1->change_time = name->dos.change_time;
272
return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
273
XATTR_DOSATTRIB_NAME, &attrib,
274
(ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
279
load the set of DOS EAs
281
NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
282
struct xattr_DosEAs *eas)
286
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
289
status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME,
290
eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs);
291
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
298
save the set of DOS EAs
300
NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
301
struct xattr_DosEAs *eas)
303
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
306
return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas,
307
(ndr_push_flags_fn_t)ndr_push_xattr_DosEAs);
312
load the set of streams from extended attributes
314
NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
315
struct xattr_DosStreams *streams)
318
ZERO_STRUCTP(streams);
319
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
322
status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd,
323
XATTR_DOSSTREAMS_NAME,
325
(ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams);
326
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
333
save the set of streams into filesystem xattr
335
NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
336
struct xattr_DosStreams *streams)
338
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
341
return pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
342
XATTR_DOSSTREAMS_NAME,
344
(ndr_push_flags_fn_t)ndr_push_xattr_DosStreams);
349
load the current ACL from extended attributes
351
NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
352
struct xattr_NTACL *acl)
356
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
357
return NT_STATUS_NOT_FOUND;
359
status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd,
362
(ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
367
save the acl for a file into filesystem xattr
369
NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
370
struct xattr_NTACL *acl)
375
if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
379
/* this xattr is in the "system" namespace, so we need
380
admin privileges to set it */
381
privs = root_privileges();
382
status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd,
385
(ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
391
create a zero length xattr with the given name
393
NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs,
394
const char *fname, int fd,
395
const char *attr_prefix,
396
const char *attr_name)
399
DATA_BLOB blob = data_blob(NULL, 0);
400
char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
402
return NT_STATUS_NO_MEMORY;
404
status = push_xattr_blob(pvfs, aname, fname, fd, &blob);
411
delete a xattr with the given name
413
NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs,
414
const char *fname, int fd,
415
const char *attr_prefix,
416
const char *attr_name)
419
char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
421
return NT_STATUS_NO_MEMORY;
423
status = delete_xattr(pvfs, aname, fname, fd);
429
load a xattr with the given name
431
NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs,
433
const char *fname, int fd,
434
const char *attr_prefix,
435
const char *attr_name,
436
size_t estimated_size,
440
char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name);
442
return NT_STATUS_NO_MEMORY;
444
status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob);
450
save a xattr with the given name
452
NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs,
453
const char *fname, int fd,
454
const char *attr_prefix,
455
const char *attr_name,
456
const DATA_BLOB *blob)
459
char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name);
461
return NT_STATUS_NO_MEMORY;
463
status = push_xattr_blob(pvfs, aname, fname, fd, blob);
470
probe for system support for xattrs
472
void pvfs_xattr_probe(struct pvfs_state *pvfs)
474
TALLOC_CTX *tmp_ctx = talloc_new(pvfs);
476
pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory,
478
pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory,
480
talloc_free(tmp_ctx);