diff options
Diffstat (limited to 'source4/ntvfs/posix/xattr_tdb.c')
-rw-r--r-- | source4/ntvfs/posix/xattr_tdb.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/xattr_tdb.c b/source4/ntvfs/posix/xattr_tdb.c new file mode 100644 index 0000000000..08a2ea4c18 --- /dev/null +++ b/source4/ntvfs/posix/xattr_tdb.c @@ -0,0 +1,232 @@ +/* + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.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 pvfs_state *pvfs, 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(pvfs, 0); + + status = pull_xattr_blob_tdb(pvfs, 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=blob.data; s < (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_p(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(pvfs, XATTR_LIST_ATTR, fname, fd, &blob); + talloc_free(mem_ctx); + + return status; +} + +/* + form a key for using in the ea_db +*/ +static NTSTATUS get_ea_db_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_p(mem_ctx, char, 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_db tdb +*/ +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) +{ + TDB_DATA tkey, tdata; + NTSTATUS status; + + status = get_ea_db_key(mem_ctx, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + tdata = tdb_fetch(pvfs->ea_db->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; +} + +/* + push a xattr as a blob, using ea_db +*/ +NTSTATUS push_xattr_blob_tdb(struct pvfs_state *pvfs, + const char *attr_name, + const char *fname, + int fd, + const DATA_BLOB *blob) +{ + TDB_DATA tkey, tdata; + NTSTATUS status; + + status = get_ea_db_key(pvfs, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + tdata.dptr = blob->data; + tdata.dsize = blob->length; + + if (tdb_chainlock(pvfs->ea_db->tdb, tkey) != 0) { + talloc_free(tkey.dptr); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + status = xattr_tdb_add_list(pvfs, attr_name, fname, fd); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + if (tdb_store(pvfs->ea_db->tdb, tkey, tdata, TDB_REPLACE) == -1) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + } + +done: + tdb_chainunlock(pvfs->ea_db->tdb, tkey); + talloc_free(tkey.dptr); + return status; +} + + +/* + 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_db_key(NULL, attr_name, fname, fd, &tkey); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (tdb_delete(pvfs->ea_db->tdb, tkey) == -1) { + 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(pvfs, 0); + 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=blob.data; s < (char *)(blob.data+blob.length); s += strlen(s) + 1) { + delete_xattr_tdb(pvfs, s, fname, -1); + } + + return delete_xattr_tdb(pvfs, XATTR_LIST_ATTR, fname, -1); +} |