summaryrefslogtreecommitdiff
path: root/source4/ntvfs
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-11-05 07:29:02 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:05:30 -0500
commit9fe5fa11d637252f1fbe79c7baf778e2d3cdade2 (patch)
tree40f628c02dcc23d3ec4724e43cb9a6fcdeb5c548 /source4/ntvfs
parent0a8dff9e475aea5312ecc4bc283e8007ee653185 (diff)
downloadsamba-9fe5fa11d637252f1fbe79c7baf778e2d3cdade2.tar.gz
samba-9fe5fa11d637252f1fbe79c7baf778e2d3cdade2.tar.bz2
samba-9fe5fa11d637252f1fbe79c7baf778e2d3cdade2.zip
r3545: initial support for using extended attributes to hold extended dos attributes of files.
I decided to use IDL/NDR to encode the attribute, as it gives us a simple way to describe and extend the saved attributes. The xattr code needs to hook into quite a few more places in the pvfs code, but this at least gets the basics done. I will start encoding alternate data streams streams, DOS EAs etc soon using the same basic mechanism. I'll probably stick to "version 1" for the xattr.idl for quite a while even though it will be changing, as I don't expect anyone to be deploying this in production just yet. Once we have production users we will need to keep compatibility by supporting all the old version numbers in xattr.idl. (This used to be commit c54253ed1b7dce1d14f43e747da61089aea87094)
Diffstat (limited to 'source4/ntvfs')
-rw-r--r--source4/ntvfs/posix/config.m413
-rw-r--r--source4/ntvfs/posix/config.mk9
-rw-r--r--source4/ntvfs/posix/pvfs_fileinfo.c56
-rw-r--r--source4/ntvfs/posix/pvfs_open.c14
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c10
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c17
-rw-r--r--source4/ntvfs/posix/pvfs_xattr.c197
-rw-r--r--source4/ntvfs/posix/vfs_posix.c6
-rw-r--r--source4/ntvfs/posix/vfs_posix.h1
9 files changed, 291 insertions, 32 deletions
diff --git a/source4/ntvfs/posix/config.m4 b/source4/ntvfs/posix/config.m4
index b1de4c20e5..2fb69b65b0 100644
--- a/source4/ntvfs/posix/config.m4
+++ b/source4/ntvfs/posix/config.m4
@@ -1,4 +1,3 @@
-SMB_MODULE_MK(ntvfs_posix, NTVFS, STATIC, ntvfs/config.mk)
dnl #############################################
@@ -22,4 +21,16 @@ if test x"$ac_cv_decl_have_stat_tv_nsec" = x"yes"; then
AC_DEFINE(HAVE_STAT_TV_NSEC,1,[Whether stat has tv_nsec nanosecond fields])
fi
+dnl ############################################
+dnl use flistxattr as the key function for having
+dnl sufficient xattr support for posix xattr backend
+AC_CHECK_HEADERS(sys/attributes.h attr/xattr.h sys/xattr.h)
+AC_SEARCH_LIBS(flistxattr, [attr])
+
+if test x"$ac_cv_func_flistxattr" = x"yes"; then
+ SMB_MODULE_DEFAULT(posix_xattr, STATIC)
+ AC_DEFINE(HAVE_XATTR_SUPPORT,1,[Whether we have xattr support])
+fi
+SMB_MODULE_MK(posix_xattr, NTVFS, NOT, ntvfs/posix/config.mk)
+SMB_MODULE_MK(ntvfs_posix, NTVFS, STATIC, ntvfs/config.mk)
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk
index 4918ee61eb..d44200d8c3 100644
--- a/source4/ntvfs/posix/config.mk
+++ b/source4/ntvfs/posix/config.mk
@@ -1,4 +1,13 @@
################################################
+# Start MODULE posix_xattr
+[MODULE::posix_xattr]
+INIT_OBJ_FILES = \
+ ntvfs/posix/pvfs_xattr.o
+# End MODULE posix_xattr
+################################################
+
+
+################################################
# Start MODULE ntvfs_posix
[MODULE::ntvfs_posix]
INIT_OBJ_FILES = \
diff --git a/source4/ntvfs/posix/pvfs_fileinfo.c b/source4/ntvfs/posix/pvfs_fileinfo.c
index 42aad1a20e..49678e5998 100644
--- a/source4/ntvfs/posix/pvfs_fileinfo.c
+++ b/source4/ntvfs/posix/pvfs_fileinfo.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "include/includes.h"
+#include "includes.h"
#include "vfs_posix.h"
@@ -45,14 +45,16 @@ static uint32_t dos_mode_from_stat(struct pvfs_state *pvfs, struct stat *st)
if ((st->st_mode & S_IWUSR) == 0)
result |= FILE_ATTRIBUTE_READONLY;
- if ((pvfs->flags & PVFS_FLAG_MAP_ARCHIVE) && ((st->st_mode & S_IXUSR) != 0))
- result |= FILE_ATTRIBUTE_ARCHIVE;
-
- if ((pvfs->flags & PVFS_FLAG_MAP_SYSTEM) && ((st->st_mode & S_IXGRP) != 0))
- result |= FILE_ATTRIBUTE_SYSTEM;
-
- if ((pvfs->flags & PVFS_FLAG_MAP_HIDDEN) && ((st->st_mode & S_IXOTH) != 0))
- result |= FILE_ATTRIBUTE_HIDDEN;
+ if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
+ if ((pvfs->flags & PVFS_FLAG_MAP_ARCHIVE) && ((st->st_mode & S_IXUSR) != 0))
+ result |= FILE_ATTRIBUTE_ARCHIVE;
+
+ if ((pvfs->flags & PVFS_FLAG_MAP_SYSTEM) && ((st->st_mode & S_IXGRP) != 0))
+ result |= FILE_ATTRIBUTE_SYSTEM;
+
+ if ((pvfs->flags & PVFS_FLAG_MAP_HIDDEN) && ((st->st_mode & S_IXOTH) != 0))
+ result |= FILE_ATTRIBUTE_HIDDEN;
+ }
if (S_ISDIR(st->st_mode))
result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
@@ -74,7 +76,7 @@ static uint32_t dos_mode_from_stat(struct pvfs_state *pvfs, struct stat *st)
/*
fill in the dos file attributes for a file
*/
-NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name)
+NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
{
/* make directories appear as size 0 */
if (S_ISDIR(name->st.st_mode)) {
@@ -98,6 +100,12 @@ NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name)
name->dos.ea_size = 0;
name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino;
+#if HAVE_XATTR_SUPPORT
+ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
+ return pvfs_xattr_load(pvfs, name, fd);
+ }
+#endif
+
return NT_STATUS_OK;
}
@@ -117,19 +125,21 @@ mode_t pvfs_fileperms(struct pvfs_state *pvfs, uint32 attrib)
mode |= S_IWUSR;
}
- if ((attrib & FILE_ATTRIBUTE_ARCHIVE) &&
- (pvfs->flags & PVFS_FLAG_MAP_ARCHIVE)) {
- mode |= S_IXUSR;
- }
-
- if ((attrib & FILE_ATTRIBUTE_SYSTEM) &&
- (pvfs->flags & PVFS_FLAG_MAP_SYSTEM)) {
- mode |= S_IXGRP;
- }
-
- if ((attrib & FILE_ATTRIBUTE_HIDDEN) &&
- (pvfs->flags & PVFS_FLAG_MAP_HIDDEN)) {
- mode |= S_IXOTH;
+ if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
+ if ((attrib & FILE_ATTRIBUTE_ARCHIVE) &&
+ (pvfs->flags & PVFS_FLAG_MAP_ARCHIVE)) {
+ mode |= S_IXUSR;
+ }
+
+ if ((attrib & FILE_ATTRIBUTE_SYSTEM) &&
+ (pvfs->flags & PVFS_FLAG_MAP_SYSTEM)) {
+ mode |= S_IXGRP;
+ }
+
+ if ((attrib & FILE_ATTRIBUTE_HIDDEN) &&
+ (pvfs->flags & PVFS_FLAG_MAP_HIDDEN)) {
+ mode |= S_IXOTH;
+ }
}
return mode;
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index c8f96849ec..ed6da83e73 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "include/includes.h"
+#include "includes.h"
#include "vfs_posix.h"
#include "system/time.h"
#include "system/filesys.h"
@@ -330,6 +330,14 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
return status;
}
+
+#if HAVE_XATTR_SUPPORT
+ name->dos.attrib = io->ntcreatex.in.file_attr;
+ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
+ status = pvfs_xattr_save(pvfs, name, fd);
+ }
+#endif
+
/* form the lock context used for byte range locking and
opendb locking */
status = pvfs_locking_key(name, f, &f->locking_key);
@@ -472,6 +480,10 @@ static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
return;
}
+ /* re-mark it async, just in case someone up the chain does
+ paranoid checking */
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+
/* send the reply up the chain */
req->async_states->status = status;
req->async_states->send_fn(req);
diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c
index 551b05b248..30602b964a 100644
--- a/source4/ntvfs/posix/pvfs_resolve.c
+++ b/source4/ntvfs/posix/pvfs_resolve.c
@@ -27,7 +27,7 @@
*/
-#include "include/includes.h"
+#include "includes.h"
#include "vfs_posix.h"
#include "system/dir.h"
@@ -175,7 +175,7 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename *
name->full_name = partial_name;
if (name->exists) {
- return pvfs_fill_dos_info(pvfs, name);
+ return pvfs_fill_dos_info(pvfs, name, -1);
}
return NT_STATUS_OK;
@@ -446,7 +446,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
/* if we can stat() the full name now then we are done */
if (stat((*name)->full_name, &(*name)->st) == 0) {
(*name)->exists = True;
- return pvfs_fill_dos_info(pvfs, *name);
+ return pvfs_fill_dos_info(pvfs, *name, -1);
}
/* search for a matching filename */
@@ -489,7 +489,7 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
(*name)->original_name = talloc_strdup(*name, fname);
(*name)->stream_name = NULL;
- status = pvfs_fill_dos_info(pvfs, *name);
+ status = pvfs_fill_dos_info(pvfs, *name, -1);
return status;
}
@@ -534,5 +534,5 @@ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
name->exists = True;
- return pvfs_fill_dos_info(pvfs, name);
+ return pvfs_fill_dos_info(pvfs, name, fd);
}
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index 8a4c6e433d..fe489c2e69 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -20,7 +20,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "include/includes.h"
+#include "includes.h"
#include "vfs_posix.h"
#include "system/time.h"
@@ -163,6 +163,13 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
}
}
+ *f->name = newstats;
+
+#if HAVE_XATTR_SUPPORT
+ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
+ return pvfs_xattr_save(pvfs, f->name, f->fd);
+ }
+#endif
return NT_STATUS_OK;
}
@@ -287,6 +294,14 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
}
}
+ *name = newstats;
+
+#if HAVE_XATTR_SUPPORT
+ if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
+ return pvfs_xattr_save(pvfs, name, -1);
+ }
+#endif
+
return NT_STATUS_OK;
}
diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c
new file mode 100644
index 0000000000..24fa49108a
--- /dev/null
+++ b/source4/ntvfs/posix/pvfs_xattr.c
@@ -0,0 +1,197 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ POSIX NTVFS backend - xattr support
+
+ 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"
+#include "librpc/gen_ndr/ndr_xattr.h"
+
+
+/*
+ pull a xattr as a blob, from either a file or a file descriptor
+*/
+static NTSTATUS pull_xattr_blob(TALLOC_CTX *mem_ctx,
+ const char *attr_name,
+ const char *fname,
+ int fd,
+ size_t estimated_size,
+ DATA_BLOB *blob)
+{
+ 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 map_nt_error_from_unix(errno);
+ }
+
+ blob->length = ret;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ push a xattr as a blob, from either a file or a file descriptor
+*/
+static NTSTATUS push_xattr_blob(TALLOC_CTX *mem_ctx,
+ const char *attr_name,
+ const char *fname,
+ int fd,
+ const DATA_BLOB *blob)
+{
+ 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 map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ fill in file attributes from extended attributes
+*/
+NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
+{
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct xattr_DosAttrib attrib;
+ TALLOC_CTX *mem_ctx = talloc(name, 0);
+ struct xattr_DosInfo1 *info1;
+
+ status = pull_xattr_blob(mem_ctx, XATTR_DOSATTRIB_NAME, name->full_name,
+ fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob);
+
+ /* if the filesystem doesn't support them, then tell pvfs not to try again */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ DEBUG(5,("pvfs_xattr: xattr not supported in filesystem\n"));
+ pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
+ }
+
+ /* 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;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* pull the blob */
+ status = ndr_pull_struct_blob(&blob, mem_ctx, &attrib,
+ (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ switch (attrib.version) {
+ case 1:
+ info1 = &attrib.info.info1;
+ name->dos.attrib = info1->attrib;
+ name->dos.ea_size = info1->ea_size;
+ if (name->st.st_size == info1->size) {
+ name->dos.alloc_size = info1->alloc_size;
+ }
+ if (info1->create_time != 0) {
+ name->dos.create_time = info1->create_time;
+ }
+ if (info1->change_time != 0) {
+ name->dos.change_time = info1->change_time;
+ }
+ break;
+
+ default:
+ DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n",
+ attrib.version, name->full_name));
+ talloc_free(mem_ctx);
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ talloc_free(mem_ctx);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ save the file attribute into into the xattr
+*/
+NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
+{
+ struct xattr_DosAttrib attrib;
+ struct xattr_DosInfo1 *info1;
+ TALLOC_CTX *mem_ctx = talloc(name, 0);
+ DATA_BLOB blob;
+ NTSTATUS status;
+
+ attrib.version = 1;
+ info1 = &attrib.info.info1;
+
+ info1->attrib = name->dos.attrib;
+ info1->ea_size = name->dos.ea_size;
+ info1->size = name->st.st_size;
+ info1->alloc_size = name->dos.alloc_size;
+ info1->create_time = name->dos.create_time;
+ info1->change_time = name->dos.change_time;
+
+ status = ndr_push_struct_blob(&blob, mem_ctx, &attrib,
+ (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ status = push_xattr_blob(mem_ctx, XATTR_DOSATTRIB_NAME, name->full_name, fd, &blob);
+ talloc_free(mem_ctx);
+
+ return status;
+}
diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c
index 2f0f38dd22..da4296d062 100644
--- a/source4/ntvfs/posix/vfs_posix.c
+++ b/source4/ntvfs/posix/vfs_posix.c
@@ -24,7 +24,7 @@
This is the default backend
*/
-#include "include/includes.h"
+#include "includes.h"
#include "vfs_posix.h"
@@ -44,6 +44,10 @@ static void pvfs_setup_options(struct pvfs_state *pvfs)
if (lp_strict_locking(snum)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
if (lp_ci_filesystem(snum)) pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
+#if HAVE_XATTR_SUPPORT
+ if (lp_parm_bool(snum, "posix", "xattr", True)) pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
+#endif
+
pvfs->sharing_violation_delay = 1000000;
delay = lp_parm_int(snum, "posix", "sharedelay");
if (delay != -1) {
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 4ee06723ac..64b9a0d653 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -161,6 +161,7 @@ struct pvfs_mangle_context {
#define PVFS_FLAG_READONLY (1<<4)
#define PVFS_FLAG_STRICT_SYNC (1<<5)
#define PVFS_FLAG_STRICT_LOCKING (1<<6)
+#define PVFS_FLAG_XATTR_ENABLE (1<<7)
/* forward declare some anonymous structures */
struct pvfs_dir;