From 7b4d511bc638b5c927dacc324628bd5db30e6dda Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 3 Apr 2012 13:35:39 +1000 Subject: s4-ntvfs: Rename xattr_tdb.c to posix_eadb.c and make more generally useful This is now a small library, to be called from ntvfs, python and vfs_posix_eadb. The rename makes it clear that this has a different DB format to that used by vfs_xattr_tdb, and matches the posix:eadb smb.conf parameter used to configure it. Andrew Bartlett --- source4/ntvfs/posix/posix_eadb.c | 291 +++++++++++++++++++++++++++++++ source4/ntvfs/posix/posix_eadb.h | 20 +++ source4/ntvfs/posix/pvfs_xattr.c | 5 +- source4/ntvfs/posix/python/pyxattr_tdb.c | 7 +- source4/ntvfs/posix/wscript_build | 13 +- source4/ntvfs/posix/xattr_tdb.c | 256 --------------------------- 6 files changed, 327 insertions(+), 265 deletions(-) create mode 100644 source4/ntvfs/posix/posix_eadb.c create mode 100644 source4/ntvfs/posix/posix_eadb.h delete mode 100644 source4/ntvfs/posix/xattr_tdb.c (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/posix_eadb.c b/source4/ntvfs/posix/posix_eadb.c new file mode 100644 index 0000000000..3f5a5b8e30 --- /dev/null +++ b/source4/ntvfs/posix/posix_eadb.c @@ -0,0 +1,291 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - xattr support using a tdb + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "lib/tdb_wrap/tdb_wrap.h" +#include "tdb_compat.h" +#include "vfs_posix.h" +#include "posix_eadb.h" + +#define XATTR_LIST_ATTR ".xattr_list" + +/* + we need to maintain a list of attributes on each file, so that unlink + can automatically clean them up +*/ +static NTSTATUS posix_eadb_add_list(struct tdb_wrap *ea_tdb, TALLOC_CTX *ctx, const char *attr_name, + const char *fname, int fd) +{ + DATA_BLOB blob; + TALLOC_CTX *mem_ctx; + const char *s; + NTSTATUS status; + size_t len; + + if (strcmp(attr_name, XATTR_LIST_ATTR) == 0) { + return NT_STATUS_OK; + } + + mem_ctx = talloc_new(ctx); + + status = pull_xattr_blob_tdb_raw(ea_tdb, mem_ctx, XATTR_LIST_ATTR, + fname, fd, 100, &blob); + if (!NT_STATUS_IS_OK(status)) { + blob = data_blob(NULL, 0); + } + + for (s=(const char *)blob.data; s < (const char *)(blob.data+blob.length); s += strlen(s) + 1) { + if (strcmp(attr_name, s) == 0) { + talloc_free(mem_ctx); + return NT_STATUS_OK; + } + } + + len = strlen(attr_name) + 1; + + blob.data = talloc_realloc(mem_ctx, blob.data, uint8_t, blob.length + len); + if (blob.data == NULL) { + talloc_free(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + memcpy(blob.data + blob.length, attr_name, len); + blob.length += len; + + status = push_xattr_blob_tdb_raw(ea_tdb, XATTR_LIST_ATTR, fname, fd, &blob); + talloc_free(mem_ctx); + + return status; +} + +/* + form a key for using in the ea_tdb +*/ +static NTSTATUS get_ea_tdb_key(TALLOC_CTX *mem_ctx, + const char *attr_name, + const char *fname, int fd, + TDB_DATA *key) +{ + struct stat st; + size_t len = strlen(attr_name); + + if (fd == -1) { + if (stat(fname, &st) == -1) { + return NT_STATUS_NOT_FOUND; + } + } else { + if (fstat(fd, &st) == -1) { + return NT_STATUS_NOT_FOUND; + } + } + + key->dptr = talloc_array(mem_ctx, uint8_t, 16 + len); + if (key->dptr == NULL) { + return NT_STATUS_NO_MEMORY; + } + key->dsize = 16 + len; + + SBVAL(key->dptr, 0, st.st_dev); + SBVAL(key->dptr, 8, st.st_ino); + memcpy(key->dptr+16, attr_name, len); + + return NT_STATUS_OK; +} + + + +/* + pull a xattr as a blob, using the ea_tdb_context tdb +*/ +NTSTATUS pull_xattr_blob_tdb_raw(struct tdb_wrap *ea_tdb, + TALLOC_CTX *mem_ctx, + const char *attr_name, + const char *fname, + int fd, + size_t estimated_size, + DATA_BLOB *blob) +{ + TDB_DATA tkey, tdata; + NTSTATUS status; + + status = get_ea_tdb_key(mem_ctx, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + tdata = tdb_fetch_compat(ea_tdb->tdb, tkey); + if (tdata.dptr == NULL) { + return NT_STATUS_NOT_FOUND; + } + + *blob = data_blob_talloc(mem_ctx, tdata.dptr, tdata.dsize); + free(tdata.dptr); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +NTSTATUS pull_xattr_blob_tdb(struct pvfs_state *pvfs_state, + TALLOC_CTX *mem_ctx, + const char *attr_name, + const char *fname, + int fd, + size_t estimated_size, + DATA_BLOB *blob) +{ + return pull_xattr_blob_tdb_raw(pvfs_state->ea_db,mem_ctx,attr_name,fname,fd,estimated_size,blob); +} + +/* + push a xattr as a blob, using ea_tdb +*/ +NTSTATUS push_xattr_blob_tdb_raw(struct tdb_wrap *ea_tdb, + const char *attr_name, + const char *fname, + int fd, + const DATA_BLOB *blob) +{ + TDB_DATA tkey, tdata; + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(ea_tdb); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + status = get_ea_tdb_key(mem_ctx, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(mem_ctx); + return status; + } + + tdata.dptr = blob->data; + tdata.dsize = blob->length; + + if (tdb_chainlock(ea_tdb->tdb, tkey) != 0) { + talloc_free(mem_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + status = posix_eadb_add_list(ea_tdb,mem_ctx, attr_name, fname, fd); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(mem_ctx); + goto done; + } + + if (tdb_store(ea_tdb->tdb, tkey, tdata, TDB_REPLACE) != 0) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + } + +done: + tdb_chainunlock(ea_tdb->tdb, tkey); + talloc_free(mem_ctx); + return status; +} +NTSTATUS push_xattr_blob_tdb(struct pvfs_state *pvfs_state, + const char *attr_name, + const char *fname, + int fd, + const DATA_BLOB *blob) +{ + return push_xattr_blob_tdb_raw(pvfs_state->ea_db, attr_name, fname, fd, blob); +} + + +/* + delete a xattr +*/ +NTSTATUS delete_posix_eadb_raw(struct tdb_wrap *ea_tdb, const char *attr_name, + const char *fname, int fd) +{ + TDB_DATA tkey; + NTSTATUS status; + + status = get_ea_tdb_key(NULL, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (tdb_delete(ea_tdb->tdb, tkey) != 0) { + talloc_free(tkey.dptr); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + talloc_free(tkey.dptr); + return NT_STATUS_OK; +} + + +/* + delete a xattr +*/ +NTSTATUS delete_posix_eadb(struct pvfs_state *pvfs_state, const char *attr_name, + const char *fname, int fd) +{ + return delete_posix_eadb_raw(pvfs_state->ea_db, + attr_name, fname, fd); +} + + +/* + delete all xattrs for a file +*/ +NTSTATUS unlink_posix_eadb_raw(struct tdb_wrap *ea_tdb, const char *fname, int fd) +{ + TALLOC_CTX *mem_ctx = talloc_new(ea_tdb); + DATA_BLOB blob; + const char *s; + NTSTATUS status; + + status = pull_xattr_blob_tdb_raw(ea_tdb, mem_ctx, XATTR_LIST_ATTR, + fname, fd, 100, &blob); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(mem_ctx); + return NT_STATUS_OK; + } + + for (s=(const char *)blob.data; s < (const char *)(blob.data+blob.length); s += strlen(s) + 1) { + delete_posix_eadb_raw(ea_tdb, s, fname, -1); + } + + status = delete_posix_eadb_raw(ea_tdb, XATTR_LIST_ATTR, fname, fd); + talloc_free(mem_ctx); + return status; +} + +/* + delete all xattrs for a file +*/ +NTSTATUS unlink_posix_eadb(struct pvfs_state *pvfs_state, const char *fname) +{ + return unlink_posix_eadb_raw(pvfs_state->ea_db, fname, -1); +} + +/* + list all xattrs for a file +*/ +NTSTATUS list_posix_eadb_raw(struct tdb_wrap *ea_tdb, TALLOC_CTX *mem_ctx, + const char *fname, int fd, + DATA_BLOB *list) +{ + return pull_xattr_blob_tdb_raw(ea_tdb, mem_ctx, XATTR_LIST_ATTR, + fname, fd, 100, list); +} diff --git a/source4/ntvfs/posix/posix_eadb.h b/source4/ntvfs/posix/posix_eadb.h new file mode 100644 index 0000000000..752d322df2 --- /dev/null +++ b/source4/ntvfs/posix/posix_eadb.h @@ -0,0 +1,20 @@ +/* + Unix SMB/CIFS implementation. Xattr manipulation bindings. + Copyright (C) Andrew Bartlett 2011 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +struct pvfs_state *pvfs; +#include "source4/ntvfs/posix/posix_eadb_proto.h" diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c index 04ad1786ac..82ce579676 100644 --- a/source4/ntvfs/posix/pvfs_xattr.c +++ b/source4/ntvfs/posix/pvfs_xattr.c @@ -24,6 +24,7 @@ #include "../lib/util/unix_privs.h" #include "librpc/gen_ndr/ndr_xattr.h" #include "param/param.h" +#include "ntvfs/posix/posix_eadb_proto.h" /* pull a xattr as a blob @@ -81,7 +82,7 @@ static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, const char *fname, int fd) { if (pvfs->ea_db) { - return delete_xattr_tdb(pvfs, attr_name, fname, fd); + return delete_posix_eadb(pvfs, attr_name, fname, fd); } return delete_xattr_system(pvfs, attr_name, fname, fd); } @@ -92,7 +93,7 @@ static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname) { if (pvfs->ea_db) { - return unlink_xattr_tdb(pvfs, fname); + return unlink_posix_eadb(pvfs, fname); } return unlink_xattr_system(pvfs, fname); } diff --git a/source4/ntvfs/posix/python/pyxattr_tdb.c b/source4/ntvfs/posix/python/pyxattr_tdb.c index 1fdae7606d..d1be879514 100644 --- a/source4/ntvfs/posix/python/pyxattr_tdb.c +++ b/source4/ntvfs/posix/python/pyxattr_tdb.c @@ -20,11 +20,12 @@ #include #include "includes.h" +#include "system/filesys.h" #include "tdb_compat.h" #include "lib/tdb_wrap/tdb_wrap.h" #include "librpc/ndr/libndr.h" #include "lib/util/wrap_xattr.h" -#include "ntvfs/posix/vfs_posix.h" +#include "ntvfs/posix/posix_eadb.h" #include "libcli/util/pyerrors.h" #include "param/pyparam.h" @@ -59,8 +60,8 @@ static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args) talloc_free(mem_ctx); return NULL; } - status = push_xattr_blob_tdb_raw(eadb, mem_ctx, attribute, filename, -1, - &blob); + status = push_xattr_blob_tdb_raw(eadb, attribute, filename, -1, + &blob); if (!NT_STATUS_IS_OK(status)) { PyErr_SetNTSTATUS(status); talloc_free(mem_ctx); diff --git a/source4/ntvfs/posix/wscript_build b/source4/ntvfs/posix/wscript_build index acceefadf6..8bd7648b82 100644 --- a/source4/ntvfs/posix/wscript_build +++ b/source4/ntvfs/posix/wscript_build @@ -31,11 +31,11 @@ bld.SAMBA_SUBSYSTEM('pvfs_aio', bld.SAMBA_MODULE('ntvfs_posix', - source='vfs_posix.c pvfs_util.c pvfs_search.c pvfs_dirlist.c pvfs_fileinfo.c pvfs_unlink.c pvfs_mkdir.c pvfs_open.c pvfs_read.c pvfs_flush.c pvfs_write.c pvfs_fsinfo.c pvfs_qfileinfo.c pvfs_setfileinfo.c pvfs_rename.c pvfs_resolve.c pvfs_shortname.c pvfs_lock.c pvfs_oplock.c pvfs_wait.c pvfs_seek.c pvfs_ioctl.c pvfs_xattr.c pvfs_streams.c pvfs_notify.c pvfs_sys.c xattr_system.c xattr_tdb.c', + source='vfs_posix.c pvfs_util.c pvfs_search.c pvfs_dirlist.c pvfs_fileinfo.c pvfs_unlink.c pvfs_mkdir.c pvfs_open.c pvfs_read.c pvfs_flush.c pvfs_write.c pvfs_fsinfo.c pvfs_qfileinfo.c pvfs_setfileinfo.c pvfs_rename.c pvfs_resolve.c pvfs_shortname.c pvfs_lock.c pvfs_oplock.c pvfs_wait.c pvfs_seek.c pvfs_ioctl.c pvfs_xattr.c pvfs_streams.c pvfs_notify.c pvfs_sys.c xattr_system.c', autoproto='vfs_posix_proto.h', subsystem='ntvfs', init_function='ntvfs_posix_init', - deps='NDR_XATTR wrap_xattr ntvfs_common MESSAGING LIBWBCLIENT_OLD pvfs_acl pvfs_aio', + deps='NDR_XATTR wrap_xattr ntvfs_common MESSAGING LIBWBCLIENT_OLD pvfs_acl pvfs_aio posix_eadb', internal_module=True ) @@ -46,10 +46,15 @@ bld.SAMBA_PYTHON('python_xattr_native', realname='samba/xattr_native.so' ) +bld.SAMBA_LIBRARY('posix_eadb', + source='posix_eadb.c', + deps='tdb tdb-wrap', + autoproto='posix_eadb_proto.h', + private_library=True) bld.SAMBA_PYTHON('python_xattr_tdb', - source='python/pyxattr_tdb.c xattr_tdb.c', - deps='ndr ldb pyparam_util share attr', + source='python/pyxattr_tdb.c', + deps='pyparam_util posix_eadb', realname='samba/xattr_tdb.so' ) diff --git a/source4/ntvfs/posix/xattr_tdb.c b/source4/ntvfs/posix/xattr_tdb.c deleted file mode 100644 index 2a320ba7a6..0000000000 --- a/source4/ntvfs/posix/xattr_tdb.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - POSIX NTVFS backend - xattr support using a tdb - - Copyright (C) Andrew Tridgell 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "lib/tdb_wrap/tdb_wrap.h" -#include "tdb_compat.h" -#include "vfs_posix.h" - -#define XATTR_LIST_ATTR ".xattr_list" - -/* - we need to maintain a list of attributes on each file, so that unlink - can automatically clean them up -*/ -static NTSTATUS xattr_tdb_add_list(struct tdb_wrap *ea_tdb, TALLOC_CTX *ctx, const char *attr_name, - const char *fname, int fd) -{ - DATA_BLOB blob; - TALLOC_CTX *mem_ctx; - const char *s; - NTSTATUS status; - size_t len; - - if (strcmp(attr_name, XATTR_LIST_ATTR) == 0) { - return NT_STATUS_OK; - } - - mem_ctx = talloc_new(ctx); - - status = pull_xattr_blob_tdb_raw(ea_tdb, mem_ctx, XATTR_LIST_ATTR, - fname, fd, 100, &blob); - if (!NT_STATUS_IS_OK(status)) { - blob = data_blob(NULL, 0); - } - - for (s=(const char *)blob.data; s < (const char *)(blob.data+blob.length); s += strlen(s) + 1) { - if (strcmp(attr_name, s) == 0) { - talloc_free(mem_ctx); - return NT_STATUS_OK; - } - } - - len = strlen(attr_name) + 1; - - blob.data = talloc_realloc(mem_ctx, blob.data, uint8_t, blob.length + len); - if (blob.data == NULL) { - talloc_free(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - memcpy(blob.data + blob.length, attr_name, len); - blob.length += len; - - status = push_xattr_blob_tdb_raw(ea_tdb,ctx, XATTR_LIST_ATTR, fname, fd, &blob); - talloc_free(mem_ctx); - - return status; -} - -/* - form a key for using in the ea_tdb -*/ -static NTSTATUS get_ea_tdb_key(TALLOC_CTX *mem_ctx, - const char *attr_name, - const char *fname, int fd, - TDB_DATA *key) -{ - struct stat st; - size_t len = strlen(attr_name); - - if (fd == -1) { - if (stat(fname, &st) == -1) { - return NT_STATUS_NOT_FOUND; - } - } else { - if (fstat(fd, &st) == -1) { - return NT_STATUS_NOT_FOUND; - } - } - - key->dptr = talloc_array(mem_ctx, uint8_t, 16 + len); - if (key->dptr == NULL) { - return NT_STATUS_NO_MEMORY; - } - key->dsize = 16 + len; - - SBVAL(key->dptr, 0, st.st_dev); - SBVAL(key->dptr, 8, st.st_ino); - memcpy(key->dptr+16, attr_name, len); - - return NT_STATUS_OK; -} - - - -/* - pull a xattr as a blob, using the ea_tdb_context tdb -*/ -NTSTATUS pull_xattr_blob_tdb_raw(struct tdb_wrap *ea_tdb, - TALLOC_CTX *mem_ctx, - const char *attr_name, - const char *fname, - int fd, - size_t estimated_size, - DATA_BLOB *blob) -{ - TDB_DATA tkey, tdata; - NTSTATUS status; - - status = get_ea_tdb_key(mem_ctx, attr_name, fname, fd, &tkey); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - tdata = tdb_fetch_compat(ea_tdb->tdb, tkey); - if (tdata.dptr == NULL) { - return NT_STATUS_NOT_FOUND; - } - - *blob = data_blob_talloc(mem_ctx, tdata.dptr, tdata.dsize); - free(tdata.dptr); - if (blob->data == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -NTSTATUS pull_xattr_blob_tdb(struct pvfs_state *pvfs, - TALLOC_CTX *mem_ctx, - const char *attr_name, - const char *fname, - int fd, - size_t estimated_size, - DATA_BLOB *blob) -{ - return pull_xattr_blob_tdb_raw(pvfs->ea_db,mem_ctx,attr_name,fname,fd,estimated_size,blob); -} - -/* - push a xattr as a blob, using ea_tdb -*/ -NTSTATUS push_xattr_blob_tdb_raw(struct tdb_wrap *ea_tdb, - TALLOC_CTX *mem_ctx, - const char *attr_name, - const char *fname, - int fd, - const DATA_BLOB *blob) -{ - TDB_DATA tkey, tdata; - NTSTATUS status; - - status = get_ea_tdb_key(mem_ctx, attr_name, fname, fd, &tkey); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - tdata.dptr = blob->data; - tdata.dsize = blob->length; - - if (tdb_chainlock(ea_tdb->tdb, tkey) != 0) { - talloc_free(tkey.dptr); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - status = xattr_tdb_add_list(ea_tdb,mem_ctx, attr_name, fname, fd); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - if (tdb_store(ea_tdb->tdb, tkey, tdata, TDB_REPLACE) != 0) { - status = NT_STATUS_INTERNAL_DB_CORRUPTION; - } - -done: - tdb_chainunlock(ea_tdb->tdb, tkey); - talloc_free(tkey.dptr); - return status; -} -NTSTATUS push_xattr_blob_tdb(struct pvfs_state *pvfs, - const char *attr_name, - const char *fname, - int fd, - const DATA_BLOB *blob) -{ - return push_xattr_blob_tdb_raw(pvfs->ea_db,pvfs,attr_name,fname,fd,blob); -} - - -/* - delete a xattr -*/ -NTSTATUS delete_xattr_tdb(struct pvfs_state *pvfs, const char *attr_name, - const char *fname, int fd) -{ - TDB_DATA tkey; - NTSTATUS status; - - status = get_ea_tdb_key(NULL, attr_name, fname, fd, &tkey); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (tdb_delete(pvfs->ea_db->tdb, tkey) != 0) { - talloc_free(tkey.dptr); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - talloc_free(tkey.dptr); - return NT_STATUS_OK; -} - - - -/* - delete all xattrs for a file -*/ -NTSTATUS unlink_xattr_tdb(struct pvfs_state *pvfs, const char *fname) -{ - TALLOC_CTX *mem_ctx = talloc_new(pvfs); - DATA_BLOB blob; - const char *s; - NTSTATUS status; - - status = pull_xattr_blob_tdb(pvfs, mem_ctx, XATTR_LIST_ATTR, - fname, -1, 100, &blob); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(mem_ctx); - return NT_STATUS_OK; - } - - for (s=(const char *)blob.data; s < (const char *)(blob.data+blob.length); s += strlen(s) + 1) { - delete_xattr_tdb(pvfs, s, fname, -1); - } - - status = delete_xattr_tdb(pvfs, XATTR_LIST_ATTR, fname, -1); - talloc_free(mem_ctx); - return status; -} -- cgit