diff options
-rw-r--r-- | source4/ntvfs/posix/config.mk | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 6 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_unlink.c | 5 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_xattr.c | 93 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 16 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 3 | ||||
-rw-r--r-- | source4/ntvfs/posix/xattr_system.c | 134 | ||||
-rw-r--r-- | source4/ntvfs/posix/xattr_tdb.c | 232 |
8 files changed, 425 insertions, 68 deletions
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 44a1625c5f..f2f7207773 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -28,7 +28,9 @@ ADD_OBJ_FILES = \ ntvfs/posix/pvfs_ioctl.o \ ntvfs/posix/pvfs_xattr.o \ ntvfs/posix/pvfs_streams.o \ - ntvfs/posix/pvfs_acl.o + ntvfs/posix/pvfs_acl.o \ + ntvfs/posix/xattr_system.o \ + ntvfs/posix/xattr_tdb.o REQUIRED_SUBSYSTEMS = NDR_XATTR ntvfs_common # End MODULE ntvfs_posix ################################################ diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index af0858f639..e31d79b9e0 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -267,6 +267,12 @@ static int pvfs_handle_destructor(void *p) if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && h->name->stream_name == NULL) { + NTSTATUS status; + status = pvfs_xattr_unlink_hook(h->pvfs, h->name->full_name); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + } if (unlink(h->name->full_name) != 0) { DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", h->name->full_name, strerror(errno))); diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c index 434577a862..f29a70600f 100644 --- a/source4/ntvfs/posix/pvfs_unlink.c +++ b/source4/ntvfs/posix/pvfs_unlink.c @@ -86,6 +86,11 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, return NT_STATUS_FILE_IS_A_DIRECTORY; } + status = pvfs_xattr_unlink_hook(pvfs, name->full_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + /* finally try the actual unlink */ if (unlink(name->full_name) == -1) { status = pvfs_map_errno(pvfs, errno); diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c index 47549499e6..4487663e8d 100644 --- a/source4/ntvfs/posix/pvfs_xattr.c +++ b/source4/ntvfs/posix/pvfs_xattr.c @@ -21,12 +21,11 @@ */ #include "includes.h" -#include "system/filesys.h" #include "vfs_posix.h" #include "librpc/gen_ndr/ndr_xattr.h" /* - pull a xattr as a blob, from either a file or a file descriptor + pull a xattr as a blob */ static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, @@ -36,45 +35,16 @@ static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs, size_t estimated_size, DATA_BLOB *blob) { -#if HAVE_XATTR_SUPPORT - int ret; - - *blob = data_blob_talloc(mem_ctx, NULL, estimated_size); - if (blob->data == NULL) { - return NT_STATUS_NO_MEMORY; - } - -again: - if (fd != -1) { - ret = fgetxattr(fd, attr_name, blob->data, estimated_size); - } else { - ret = getxattr(fname, attr_name, blob->data, estimated_size); - } - if (ret == -1 && errno == ERANGE) { - estimated_size *= 2; - blob->data = talloc_realloc(mem_ctx, blob->data, estimated_size); - if (blob->data == NULL) { - return NT_STATUS_NO_MEMORY; - } - blob->length = estimated_size; - goto again; + if (pvfs->ea_db) { + return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname, + fd, estimated_size, blob); } - - if (ret == -1) { - data_blob_free(blob); - return pvfs_map_errno(pvfs, errno); - } - - blob->length = ret; - - return NT_STATUS_OK; -#else - return NT_STATUS_NOT_SUPPORTED; -#endif + return pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname, + fd, estimated_size, blob); } /* - push a xattr as a blob, from either a file or a file descriptor + push a xattr as a blob */ static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs, const char *attr_name, @@ -82,22 +52,10 @@ static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs, int fd, const DATA_BLOB *blob) { -#if HAVE_XATTR_SUPPORT - int ret; - - if (fd != -1) { - ret = fsetxattr(fd, attr_name, blob->data, blob->length, 0); - } else { - ret = setxattr(fname, attr_name, blob->data, blob->length, 0); + if (pvfs->ea_db) { + return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob); } - if (ret == -1) { - return pvfs_map_errno(pvfs, errno); - } - - return NT_STATUS_OK; -#else - return NT_STATUS_NOT_SUPPORTED; -#endif + return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob); } @@ -107,24 +65,24 @@ static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs, static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, const char *fname, int fd) { -#if HAVE_XATTR_SUPPORT - int ret; - - if (fd != -1) { - ret = fremovexattr(fd, attr_name); - } else { - ret = removexattr(fname, attr_name); - } - if (ret == -1) { - return pvfs_map_errno(pvfs, errno); + if (pvfs->ea_db) { + return delete_xattr_tdb(pvfs, attr_name, fname, fd); } + return delete_xattr_system(pvfs, attr_name, fname, fd); +} - return NT_STATUS_OK; -#else - return NT_STATUS_NOT_SUPPORTED; -#endif +/* + a hook called on unlink - allows the tdb xattr backend to cleanup +*/ +NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname) +{ + if (pvfs->ea_db) { + return unlink_xattr_tdb(pvfs, fname); + } + return unlink_xattr_system(pvfs, fname); } + /* load a NDR structure from a xattr */ @@ -211,7 +169,7 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name /* not having a DosAttrib is not an error */ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { talloc_free(mem_ctx); - return NT_STATUS_OK; + return pvfs_stream_info(pvfs, name, fd); } if (!NT_STATUS_IS_OK(status)) { @@ -493,3 +451,4 @@ NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, talloc_free(aname); return status; } + diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index ff3d3448f2..6f4de1e038 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -35,6 +35,7 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) { int snum = pvfs->tcon->service; int delay; + const char *eadb; if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; @@ -66,6 +67,21 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) FS_ATTR_UNICODE_ON_DISK | FS_ATTR_SPARSE_FILES; + /* allow xattrs to be stored in a external tdb */ + eadb = lp_parm_string(snum, "posix", "eadb"); + if (eadb != NULL) { + pvfs->ea_db = tdb_wrap_open(pvfs, eadb, 50000, + TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + if (pvfs->ea_db != NULL) { + pvfs->flags |= PVFS_FLAG_XATTR_ENABLE; + } else { + DEBUG(0,("Failed to open eadb '%s' - %s\n", + eadb, strerror(errno))); + pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE; + } + } + + if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) { pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS; } diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 16c6f807e9..e80790f6fa 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -57,6 +57,9 @@ struct pvfs_state { /* filesystem attributes (see FS_ATTR_*) */ uint32_t fs_attribs; + + /* if posix:eadb is set, then this gets setup */ + struct tdb_wrap *ea_db; }; /* this is the basic information needed about a file from the filesystem */ diff --git a/source4/ntvfs/posix/xattr_system.c b/source4/ntvfs/posix/xattr_system.c new file mode 100644 index 0000000000..c86ee0bd87 --- /dev/null +++ b/source4/ntvfs/posix/xattr_system.c @@ -0,0 +1,134 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - xattr support using filesystem xattrs + + 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 "system/filesys.h" +#include "vfs_posix.h" + +/* + pull a xattr as a blob, from either a file or a file descriptor +*/ +NTSTATUS pull_xattr_blob_system(struct pvfs_state *pvfs, + TALLOC_CTX *mem_ctx, + const char *attr_name, + const char *fname, + int fd, + size_t estimated_size, + DATA_BLOB *blob) +{ +#if HAVE_XATTR_SUPPORT + int ret; + + *blob = data_blob_talloc(mem_ctx, NULL, estimated_size); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + +again: + if (fd != -1) { + ret = fgetxattr(fd, attr_name, blob->data, estimated_size); + } else { + ret = getxattr(fname, attr_name, blob->data, estimated_size); + } + if (ret == -1 && errno == ERANGE) { + estimated_size *= 2; + blob->data = talloc_realloc(mem_ctx, blob->data, estimated_size); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + blob->length = estimated_size; + goto again; + } + + if (ret == -1) { + data_blob_free(blob); + return pvfs_map_errno(pvfs, errno); + } + + blob->length = ret; + + return NT_STATUS_OK; +#else + return NT_STATUS_NOT_SUPPORTED; +#endif +} + +/* + push a xattr as a blob, from either a file or a file descriptor +*/ +NTSTATUS push_xattr_blob_system(struct pvfs_state *pvfs, + const char *attr_name, + const char *fname, + int fd, + const DATA_BLOB *blob) +{ +#if HAVE_XATTR_SUPPORT + int ret; + + if (fd != -1) { + ret = fsetxattr(fd, attr_name, blob->data, blob->length, 0); + } else { + ret = setxattr(fname, attr_name, blob->data, blob->length, 0); + } + if (ret == -1) { + return pvfs_map_errno(pvfs, errno); + } + + return NT_STATUS_OK; +#else + return NT_STATUS_NOT_SUPPORTED; +#endif +} + + +/* + delete a xattr +*/ +NTSTATUS delete_xattr_system(struct pvfs_state *pvfs, const char *attr_name, + const char *fname, int fd) +{ +#if HAVE_XATTR_SUPPORT + int ret; + + if (fd != -1) { + ret = fremovexattr(fd, attr_name); + } else { + ret = removexattr(fname, attr_name); + } + if (ret == -1) { + return pvfs_map_errno(pvfs, errno); + } + + return NT_STATUS_OK; +#else + return NT_STATUS_NOT_SUPPORTED; +#endif +} + +/* + unlink a file - cleanup any xattrs +*/ +NTSTATUS unlink_xattr_system(struct pvfs_state *pvfs, const char *fname) +{ + /* nothing needs to be done for filesystem based xattrs */ + return NT_STATUS_OK; +} 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); +} |