summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/gpfs.c20
-rw-r--r--source3/modules/nfs4_acls.c277
-rw-r--r--source3/modules/nfs4_acls.h7
-rw-r--r--source3/modules/vfs_afsacl.c125
-rw-r--r--source3/modules/vfs_aixacl.c13
-rw-r--r--source3/modules/vfs_aixacl2.c55
-rw-r--r--source3/modules/vfs_audit.c12
-rw-r--r--source3/modules/vfs_cacheprime.c24
-rw-r--r--source3/modules/vfs_cap.c12
-rw-r--r--source3/modules/vfs_catia.c3
-rw-r--r--source3/modules/vfs_commit.c11
-rw-r--r--source3/modules/vfs_default.c270
-rw-r--r--source3/modules/vfs_extd_audit.c12
-rw-r--r--source3/modules/vfs_fake_perms.c4
-rw-r--r--source3/modules/vfs_full_audit.c171
-rw-r--r--source3/modules/vfs_gpfs.c339
-rw-r--r--source3/modules/vfs_gpfs.h32
-rw-r--r--source3/modules/vfs_hpuxacl.c15
-rw-r--r--source3/modules/vfs_irixacl.c7
-rw-r--r--source3/modules/vfs_posixacl.c9
-rw-r--r--source3/modules/vfs_prealloc.c11
-rw-r--r--source3/modules/vfs_readahead.c29
-rw-r--r--source3/modules/vfs_recycle.c4
-rw-r--r--source3/modules/vfs_shadow_copy2.c637
-rw-r--r--source3/modules/vfs_solarisacl.c17
-rw-r--r--source3/modules/vfs_streams_depot.c641
-rw-r--r--source3/modules/vfs_streams_xattr.c685
-rw-r--r--source3/modules/vfs_tru64acl.c11
-rw-r--r--source3/modules/vfs_tsmsm.c341
-rw-r--r--source3/modules/vfs_xattr_tdb.c755
-rw-r--r--source3/modules/vfs_zfsacl.c52
31 files changed, 4094 insertions, 507 deletions
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c
index 300e90fa69..590dbac26f 100644
--- a/source3/modules/gpfs.c
+++ b/source3/modules/gpfs.c
@@ -22,9 +22,11 @@
#ifdef HAVE_GPFS
#include "gpfs_gpl.h"
+#include "vfs_gpfs.h"
static void *libgpfs_handle = NULL;
static bool gpfs_share_modes;
+static bool gpfs_leases;
static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType);
@@ -42,7 +44,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
if (!gpfs_share_modes) {
return True;
}
-
+
if (gpfs_set_share_fn == NULL) {
return False;
}
@@ -88,7 +90,7 @@ int set_gpfs_lease(int fd, int leasetype)
{
int gpfs_type = GPFS_LEASE_NONE;
- if (!gpfs_share_modes) {
+ if (!gpfs_leases) {
return True;
}
@@ -103,6 +105,13 @@ int set_gpfs_lease(int fd, int leasetype)
if (leasetype == F_WRLCK) {
gpfs_type = GPFS_LEASE_WRITE;
}
+
+ /* we unconditionally set CAP_LEASE, rather than looking for
+ -1/EACCES as there is a bug in some versions of
+ libgpfs_gpl.so which results in a leaked fd on /dev/ss0
+ each time we try this with the wrong capabilities set
+ */
+ linux_set_lease_capability();
return gpfs_set_lease_fn(fd, gpfs_type);
}
@@ -172,11 +181,8 @@ void init_gpfs(void)
goto failed;
}
- if (lp_parm_bool(-1, "gpfs", "sharemodes", True)) {
- gpfs_share_modes = True;
- } else {
- gpfs_share_modes = False;
- }
+ gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True);
+ gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True);
return;
diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
index edcc52261c..0c3d010dcd 100644
--- a/source3/modules/nfs4_acls.c
+++ b/source3/modules/nfs4_acls.c
@@ -20,6 +20,9 @@
#include "includes.h"
#include "nfs4_acls.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_ACLS
+
#define SMBACL4_PARAM_TYPE_NAME "nfs4"
#define SMB_ACE4_INT_MAGIC 0x76F8A967
@@ -161,24 +164,35 @@ uint32 smb_get_naces(SMB4ACL_T *acl)
return aclint->naces;
}
-static int smbacl4_GetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
+static int smbacl4_GetFileOwner(struct connection_struct *conn,
+ const char *filename,
+ SMB_STRUCT_STAT *psbuf)
{
memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+
+ /* Get the stat struct for the owner info. */
+ if (SMB_VFS_STAT(conn, filename, psbuf) != 0)
+ {
+ DEBUG(8, ("SMB_VFS_STAT failed with error %s\n",
+ strerror(errno)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
+{
+ memset(psbuf, 0, sizeof(SMB_STRUCT_STAT));
+
if (fsp->is_directory || fsp->fh->fd == -1) {
- /* Get the stat struct for the owner info. */
- if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name, psbuf) != 0)
- {
- DEBUG(8, ("SMB_VFS_STAT failed with error %s\n",
- strerror(errno)));
- return -1;
- }
- } else {
- if (SMB_VFS_FSTAT(fsp,fsp->fh->fd, psbuf) != 0)
- {
- DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
- strerror(errno)));
- return -1;
- }
+ return smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, psbuf);
+ }
+ if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
+ {
+ DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
+ strerror(errno)));
+ return -1;
}
return 0;
@@ -257,30 +271,24 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, SMB4ACL_T *acl, /* in */
return True;
}
-NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp,
+static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
uint32 security_info,
SEC_DESC **ppdesc, SMB4ACL_T *acl)
{
int good_aces = 0;
- SMB_STRUCT_STAT sbuf;
DOM_SID sid_owner, sid_group;
size_t sd_size = 0;
SEC_ACE *nt_ace_list = NULL;
SEC_ACL *psa = NULL;
TALLOC_CTX *mem_ctx = talloc_tos();
- DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
-
if (acl==NULL || smb_get_naces(acl)==0)
return NT_STATUS_ACCESS_DENIED; /* special because we
* shouldn't alloc 0 for
* win */
- if (smbacl4_GetFileOwner(fsp, &sbuf))
- return map_nt_error_from_unix(errno);
-
- uid_to_sid(&sid_owner, sbuf.st_uid);
- gid_to_sid(&sid_group, sbuf.st_gid);
+ uid_to_sid(&sid_owner, sbuf->st_uid);
+ gid_to_sid(&sid_group, sbuf->st_gid);
if (smbacl4_nfs42win(mem_ctx, acl, &sid_owner, &sid_group, &nt_ace_list, &good_aces)==False) {
DEBUG(8,("smbacl4_nfs42win failed\n"));
@@ -303,12 +311,43 @@ NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp,
return NT_STATUS_NO_MEMORY;
}
- DEBUG(10, ("smb_get_nt_acl_nfs4 successfully exited with sd_size %d\n",
- sec_desc_size(*ppdesc)));
+ DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with sd_size %d\n",
+ ndr_size_security_descriptor(*ppdesc, 0)));
return NT_STATUS_OK;
}
+NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
+
+ if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl);
+}
+
+NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
+ const char *name,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
+
+ if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return smb_get_nt_acl_nfs4_common(&sbuf, security_info, ppdesc, acl);
+}
+
enum smbacl4_mode_enum {e_simple=0, e_special=1};
enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
@@ -316,6 +355,7 @@ typedef struct _smbacl4_vfs_params {
enum smbacl4_mode_enum mode;
bool do_chown;
enum smbacl4_acedup_enum acedup;
+ struct db_context *sid_mapping_table;
} smbacl4_vfs_params;
/*
@@ -415,8 +455,65 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special(
return NULL;
}
-static int smbacl4_fill_ace4(
+static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src,
+ DOM_SID *dst)
+{
+ static struct db_context *mapping_db = NULL;
+ TDB_DATA data;
+
+ if (mapping_db == NULL) {
+ const char *dbname = lp_parm_const_string(
+ -1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
+
+ if (dbname == NULL) {
+ DEBUG(10, ("%s:sidmap not defined\n",
+ SMBACL4_PARAM_TYPE_NAME));
+ return False;
+ }
+
+ become_root();
+ mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
+ O_RDONLY, 0600);
+ unbecome_root();
+
+ if (mapping_db == NULL) {
+ DEBUG(1, ("could not open sidmap: %s\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+
+ if (mapping_db->fetch(mapping_db, NULL,
+ string_term_tdb_data(sid_string_tos(src)),
+ &data) == -1) {
+ DEBUG(10, ("could not find mapping for SID %s\n",
+ sid_string_dbg(src)));
+ return False;
+ }
+
+ if ((data.dptr == NULL) || (data.dsize <= 0)
+ || (data.dptr[data.dsize-1] != '\0')) {
+ DEBUG(5, ("invalid mapping for SID %s\n",
+ sid_string_dbg(src)));
+ TALLOC_FREE(data.dptr);
+ return False;
+ }
+
+ if (!string_to_sid(dst, (char *)data.dptr)) {
+ DEBUG(1, ("invalid mapping %s for SID %s\n",
+ (char *)data.dptr, sid_string_dbg(src)));
+ TALLOC_FREE(data.dptr);
+ return False;
+ }
+
+ TALLOC_FREE(data.dptr);
+
+ return True;
+}
+
+static bool smbacl4_fill_ace4(
TALLOC_CTX *mem_ctx,
+ const char *filename,
smbacl4_vfs_params *params,
uid_t ownerUID,
gid_t ownerGID,
@@ -424,11 +521,6 @@ static int smbacl4_fill_ace4(
SMB_ACE4PROP_T *ace_v4 /* output */
)
{
- const char *dom, *name;
- enum lsa_SidType type;
- uid_t uid;
- gid_t gid;
-
DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
@@ -449,18 +541,46 @@ static int smbacl4_fill_ace4(
ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
} else {
- if (!lookup_sid(mem_ctx, &ace_nt->trustee, &dom, &name, &type)) {
- DEBUG(8, ("Could not find %s' type\n",
- sid_string_dbg(&ace_nt->trustee)));
- errno = EINVAL;
- return -1;
+ const char *dom, *name;
+ enum lsa_SidType type;
+ uid_t uid;
+ gid_t gid;
+ DOM_SID sid;
+
+ sid_copy(&sid, &ace_nt->trustee);
+
+ if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
+
+ DOM_SID mapped;
+
+ if (!nfs4_map_sid(params, &sid, &mapped)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+ "unknown\n", filename, sid_string_dbg(&sid)));
+ errno = EINVAL;
+ return False;
+ }
+
+ DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
+ "to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
+
+ if (!lookup_sid(mem_ctx, &mapped, &dom,
+ &name, &type)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
+ "mapped from %s is unknown\n",
+ filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
+ errno = EINVAL;
+ return False;
+ }
+
+ sid_copy(&sid, &mapped);
}
-
+
if (type == SID_NAME_USER) {
- if (!sid_to_uid(&ace_nt->trustee, &uid)) {
- DEBUG(2, ("Could not convert %s to uid\n",
- sid_string_dbg(&ace_nt->trustee)));
- return -1;
+ if (!sid_to_uid(&sid, &uid)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+ "convert %s to uid\n", filename,
+ sid_string_dbg(&sid)));
+ return False;
}
if (params->mode==e_special && uid==ownerUID) {
@@ -470,11 +590,13 @@ static int smbacl4_fill_ace4(
ace_v4->who.uid = uid;
}
} else { /* else group? - TODO check it... */
- if (!sid_to_gid(&ace_nt->trustee, &gid)) {
- DEBUG(2, ("Could not convert %s to gid\n",
- sid_string_dbg(&ace_nt->trustee)));
- return -1;
+ if (!sid_to_gid(&sid, &gid)) {
+ DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
+ "convert %s to gid\n", filename,
+ sid_string_dbg(&sid)));
+ return False;
}
+
ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
if (params->mode==e_special && gid==ownerGID) {
@@ -486,7 +608,7 @@ static int smbacl4_fill_ace4(
}
}
- return 0; /* OK */
+ return True; /* OK */
}
static int smbacl4_MergeIgnoreReject(
@@ -524,6 +646,7 @@ static int smbacl4_MergeIgnoreReject(
}
static SMB4ACL_T *smbacl4_win2nfs4(
+ const char *filename,
SEC_ACL *dacl,
smbacl4_vfs_params *pparams,
uid_t ownerUID,
@@ -544,9 +667,14 @@ static SMB4ACL_T *smbacl4_win2nfs4(
SMB_ACE4PROP_T ace_v4;
bool addNewACE = True;
- if (smbacl4_fill_ace4(mem_ctx, pparams, ownerUID, ownerGID,
- dacl->aces + i, &ace_v4))
- return NULL;
+ if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
+ ownerUID, ownerGID,
+ dacl->aces + i, &ace_v4)) {
+ DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
+ filename,
+ sid_string_dbg(&((dacl->aces+i)->trustee))));
+ continue;
+ }
if (pparams->acedup!=e_dontcare) {
if (smbacl4_MergeIgnoreReject(pparams->acedup, acl,
@@ -571,6 +699,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
bool result;
SMB_STRUCT_STAT sbuf;
+ bool need_chown = False;
uid_t newUID = (uid_t)-1;
gid_t newGID = (gid_t)-1;
@@ -588,7 +717,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp, &params))
return NT_STATUS_NO_MEMORY;
- if (smbacl4_GetFileOwner(fsp, &sbuf))
+ if (smbacl4_fGetFileOwner(fsp, &sbuf))
return map_nt_error_from_unix(errno);
if (params.do_chown) {
@@ -599,25 +728,33 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
return status;
}
if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
- ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
- if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
- DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) ));
- if (errno == EPERM) {
- return NT_STATUS_INVALID_OWNER;
+ ((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
+ need_chown = True;
+ }
+ if (need_chown) {
+ if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) {
+ if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+ DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
}
- return map_nt_error_from_unix(errno);
+
+ DEBUG(10,("chown %s, %u, %u succeeded.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
+ return map_nt_error_from_unix(errno);
+ need_chown = False;
+ } else { /* chown is needed, but _after_ changing acl */
+ sbuf.st_uid = newUID; /* OWNER@ in case of e_special */
+ sbuf.st_gid = newGID; /* GROUP@ in case of e_special */
}
- DEBUG(10,("chown %s, %u, %u succeeded.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
- if (smbacl4_GetFileOwner(fsp, &sbuf))
- return map_nt_error_from_unix(errno);
}
}
if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL)
{
- acl = smbacl4_win2nfs4(psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
+ acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
if (!acl)
return map_nt_error_from_unix(errno);
@@ -632,6 +769,20 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
} else
DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
+ /* Any chown pending? */
+ if (need_chown) {
+ DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+ DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+ DEBUG(10,("chown#2 %s, %u, %u succeeded.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ }
+
DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
return NT_STATUS_OK;
}
diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h
index ceb66ec094..0f783aa977 100644
--- a/source3/modules/nfs4_acls.h
+++ b/source3/modules/nfs4_acls.h
@@ -129,7 +129,12 @@ SMB4ACE_T *smb_next_ace4(SMB4ACE_T *ace);
uint32 smb_get_naces(SMB4ACL_T *acl);
-NTSTATUS smb_get_nt_acl_nfs4(files_struct *fsp,
+NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
+ uint32 security_info,
+ SEC_DESC **ppdesc, SMB4ACL_T *acl);
+
+NTSTATUS smb_get_nt_acl_nfs4(connection_struct *conn,
+ const char *name,
uint32 security_info,
SEC_DESC **ppdesc, SMB4ACL_T *acl);
diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c
index a923ce188f..e35bfabb8c 100644
--- a/source3/modules/vfs_afsacl.c
+++ b/source3/modules/vfs_afsacl.c
@@ -585,15 +585,14 @@ static uint32 nt_to_afs_file_rights(const char *filename, const SEC_ACE *ace)
return result;
}
-static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
- struct files_struct *fsp,
- uint32 security_info,
- struct security_descriptor **ppdesc)
+static size_t afs_to_nt_acl_common(struct afs_acl *afs_acl,
+ SMB_STRUCT_STAT *psbuf,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
{
SEC_ACE *nt_ace_list;
DOM_SID owner_sid, group_sid;
SEC_ACCESS mask;
- SMB_STRUCT_STAT sbuf;
SEC_ACL *psa = NULL;
int good_aces;
size_t sd_size;
@@ -601,19 +600,8 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
struct afs_ace *afs_ace;
- if (fsp->is_directory || fsp->fh->fd == -1) {
- /* Get the stat struct for the owner info. */
- if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
- return 0;
- }
- } else {
- if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
- return 0;
- }
- }
-
- uid_to_sid(&owner_sid, sbuf.st_uid);
- gid_to_sid(&group_sid, sbuf.st_gid);
+ uid_to_sid(&owner_sid, psbuf->st_uid);
+ gid_to_sid(&group_sid, psbuf->st_gid);
if (afs_acl->num_aces) {
nt_ace_list = TALLOC_ARRAY(mem_ctx, SEC_ACE, afs_acl->num_aces);
@@ -639,7 +627,7 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
continue;
}
- if (fsp->is_directory)
+ if (S_ISDIR(psbuf->st_mode))
afs_to_nt_dir_rights(afs_ace->rights, &nt_rights,
&flag);
else
@@ -656,7 +644,6 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
if (psa == NULL)
return 0;
-
*ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION,
SEC_DESC_SELF_RELATIVE,
(security_info & OWNER_SECURITY_INFORMATION)
@@ -668,6 +655,42 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
return sd_size;
}
+static size_t afs_to_nt_acl(struct afs_acl *afs_acl,
+ struct connection_struct *conn,
+ const char *name,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ /* Get the stat struct for the owner info. */
+ if(SMB_VFS_STAT(conn, name, &sbuf) != 0) {
+ return 0;
+ }
+
+ return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc);
+}
+
+static size_t afs_fto_nt_acl(struct afs_acl *afs_acl,
+ struct files_struct *fsp,
+ uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SMB_STRUCT_STAT sbuf;
+
+ if (fsp->is_directory || fsp->fh->fd == -1) {
+ /* Get the stat struct for the owner info. */
+ return afs_to_nt_acl(afs_acl, fsp->conn, fsp->fsp_name,
+ security_info, ppdesc);
+ }
+
+ if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ return 0;
+ }
+
+ return afs_to_nt_acl_common(afs_acl, &sbuf, security_info, ppdesc);
+}
+
static bool mappable_sid(const DOM_SID *sid)
{
DOM_SID domain_sid;
@@ -830,27 +853,6 @@ static bool afs_get_afs_acl(char *filename, struct afs_acl *acl)
return True;
}
-static NTSTATUS afs_get_nt_acl(struct files_struct *fsp, uint32 security_info,
- struct security_descriptor **ppdesc)
-{
- struct afs_acl acl;
- size_t sd_size;
-
- DEBUG(5, ("afs_get_nt_acl: %s\n", fsp->fsp_name));
-
- sidpts = lp_parm_bool(SNUM(fsp->conn), "afsacl", "sidpts", False);
-
- if (!afs_get_afs_acl(fsp->fsp_name, &acl)) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- sd_size = afs_to_nt_acl(&acl, fsp, security_info, ppdesc);
-
- free_afs_acl(&acl);
-
- return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
-}
-
/* For setting an AFS ACL we have to take care of the ACEs we could
* not properly map to SIDs. Merge all of them into the new ACL. */
@@ -991,22 +993,53 @@ static NTSTATUS afs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
static NTSTATUS afsacl_fget_nt_acl(struct vfs_handle_struct *handle,
struct files_struct *fsp,
- int fd, uint32 security_info,
+ uint32 security_info,
struct security_descriptor **ppdesc)
{
- return afs_get_nt_acl(fsp, security_info, ppdesc);
+ struct afs_acl acl;
+ size_t sd_size;
+
+ DEBUG(5, ("afsacl_fget_nt_acl: %s\n", fsp->fsp_name));
+
+ sidpts = lp_parm_bool(SNUM(fsp->conn), "afsacl", "sidpts", False);
+
+ if (!afs_get_afs_acl(fsp->fsp_name, &acl)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sd_size = afs_fto_nt_acl(&acl, fsp, security_info, ppdesc);
+
+ free_afs_acl(&acl);
+
+ return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
}
+
static NTSTATUS afsacl_get_nt_acl(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
const char *name, uint32 security_info,
struct security_descriptor **ppdesc)
{
- return afs_get_nt_acl(fsp, security_info, ppdesc);
+ struct afs_acl acl;
+ size_t sd_size;
+
+ DEBUG(5, ("afsacl_get_nt_acl: %s\n", name));
+
+ sidpts = lp_parm_bool(SNUM(handle->conn), "afsacl", "sidpts", False);
+
+ if (!afs_get_afs_acl(name, &acl)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sd_size = afs_to_nt_acl(&acl, handle->conn, name, security_info,
+ ppdesc);
+
+ free_afs_acl(&acl);
+
+ return (sd_size != 0) ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
}
NTSTATUS afsacl_fset_nt_acl(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, uint32 security_info_sent,
+ uint32 security_info_sent,
SEC_DESC *psd)
{
return afs_set_nt_acl(handle, fsp, security_info_sent, psd);
diff --git a/source3/modules/vfs_aixacl.c b/source3/modules/vfs_aixacl.c
index a60470ffc9..726a7f485e 100644
--- a/source3/modules/vfs_aixacl.c
+++ b/source3/modules/vfs_aixacl.c
@@ -80,8 +80,7 @@ SMB_ACL_T aixacl_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
struct acl *file_acl = (struct acl *)NULL;
@@ -93,7 +92,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle,
/* Get the acl using fstatacl */
DEBUG(10,("Entering AIX sys_acl_get_fd\n"));
- DEBUG(10,("fd is %d\n",fd));
+ DEBUG(10,("fd is %d\n",fsp->fh->fd));
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
if(file_acl == NULL) {
@@ -104,7 +103,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle,
memset(file_acl,0,BUFSIZ);
- rc = fstatacl(fd,0,file_acl,BUFSIZ);
+ rc = fstatacl(fsp->fh->fd,0,file_acl,BUFSIZ);
if( (rc == -1) && (errno == ENOSPC)) {
struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl));
if( new_acl == NULL) {
@@ -113,7 +112,7 @@ SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle,
return NULL;
}
file_acl = new_acl;
- rc = fstatacl(fd,0,file_acl,file_acl->acl_len + sizeof(struct acl));
+ rc = fstatacl(fsp->fh->fd,0,file_acl,file_acl->acl_len + sizeof(struct acl));
if( rc == -1) {
DEBUG(0,("fstatacl returned %d with errno %d\n",rc,errno));
SAFE_FREE(file_acl);
@@ -154,7 +153,7 @@ int aixacl_sys_acl_set_file(vfs_handle_struct *handle,
int aixacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
struct acl *file_acl = NULL;
unsigned int rc;
@@ -163,7 +162,7 @@ int aixacl_sys_acl_set_fd(vfs_handle_struct *handle,
if (!file_acl)
return -1;
- rc = fchacl(fd,file_acl,file_acl->acl_len);
+ rc = fchacl(fsp->fh->fd,file_acl,file_acl->acl_len);
DEBUG(10,("errno is %d\n",errno));
DEBUG(10,("return code is %d\n",rc));
SAFE_FREE(file_acl);
diff --git a/source3/modules/vfs_aixacl2.c b/source3/modules/vfs_aixacl2.c
index 756977df4f..996adbbdfe 100644
--- a/source3/modules/vfs_aixacl2.c
+++ b/source3/modules/vfs_aixacl2.c
@@ -98,7 +98,7 @@ static AIXJFS2_ACL_T *aixjfs2_getacl_alloc(const char *fname, acl_type_t *type)
return acl;
}
-static bool aixjfs2_get_nfs4_acl(files_struct *fsp,
+static bool aixjfs2_get_nfs4_acl(const char *name,
SMB4ACL_T **ppacl, bool *pretryPosix)
{
int32_t i;
@@ -108,15 +108,15 @@ static bool aixjfs2_get_nfs4_acl(files_struct *fsp,
nfs4_ace_int_t *jfs2_ace = NULL;
acl_type_t type;
- DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", fsp->fsp_name));
+ DEBUG(10,("jfs2 get_nt_acl invoked for %s\n", name));
memset(&type, 0, sizeof(acl_type_t));
type.u64 = ACL_NFS4;
- pacl = aixjfs2_getacl_alloc(fsp->fsp_name, &type);
+ pacl = aixjfs2_getacl_alloc(name, &type);
if (pacl == NULL) {
DEBUG(9, ("aixjfs2_getacl_alloc failed for %s with %s\n",
- fsp->fsp_name, strerror(errno)));
+ name, strerror(errno)));
if (errno==ENOSYS)
*pretryPosix = True;
return False;
@@ -158,38 +158,48 @@ static bool aixjfs2_get_nfs4_acl(files_struct *fsp,
return True;
}
-static NTSTATUS aixjfs2_get_nt_acl_common(files_struct *fsp,
- uint32 security_info, SEC_DESC **ppdesc)
+static NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp, uint32 security_info,
+ SEC_DESC **ppdesc)
{
SMB4ACL_T *pacl = NULL;
bool result;
bool retryPosix = False;
*ppdesc = NULL;
- result = aixjfs2_get_nfs4_acl(fsp, &pacl, &retryPosix);
+ result = aixjfs2_get_nfs4_acl(fsp->fsp_name, &pacl, &retryPosix);
if (retryPosix)
{
DEBUG(10, ("retrying with posix acl...\n"));
- return get_nt_acl(fsp, security_info, ppdesc);
+ return posix_fget_nt_acl(fsp, security_info, ppdesc);
}
if (result==False)
return NT_STATUS_ACCESS_DENIED;
- return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
}
-NTSTATUS aixjfs2_fget_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp, int fd, uint32 security_info,
- SEC_DESC **ppdesc)
-{
- return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc);
-}
-
-NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle,
+static NTSTATUS aixjfs2_get_nt_acl(vfs_handle_struct *handle,
files_struct *fsp, const char *name,
uint32 security_info, SEC_DESC **ppdesc)
{
- return aixjfs2_get_nt_acl_common(fsp, security_info, ppdesc);
+ SMB4ACL_T *pacl = NULL;
+ bool result;
+ bool retryPosix = False;
+
+ *ppdesc = NULL;
+ result = aixjfs2_get_nfs4_acl(name, &pacl, &retryPosix);
+ if (retryPosix)
+ {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_get_nt_acl(handle->conn, name security_info,
+ ppdesc);
+ }
+ if (result==False)
+ return NT_STATUS_ACCESS_DENIED;
+
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
+ pacl);
}
static SMB_ACL_T aixjfs2_get_posix_acl(const char *path, acl_type_t type)
@@ -248,8 +258,7 @@ SMB_ACL_T aixjfs2_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T aixjfs2_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
acl_type_t aixjfs2_type;
aixjfs2_type.u64 = ACL_AIXC;
@@ -389,7 +398,7 @@ static NTSTATUS aixjfs2_set_nt_acl_common(files_struct *fsp, uint32 security_inf
return result;
}
-NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
+NTSTATUS aixjfs2_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
{
return aixjfs2_set_nt_acl_common(fsp, security_info_sent, psd);
}
@@ -439,7 +448,7 @@ int aixjfs2_sys_acl_set_file(vfs_handle_struct *handle,
int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
struct acl *acl_aixc;
acl_type_t acl_type_info;
@@ -458,7 +467,7 @@ int aixjfs2_sys_acl_set_fd(vfs_handle_struct *handle,
return -1;
rc = aclx_fput(
- fd,
+ fsp->fh->fd,
SET_ACL, /* set only the ACL, not mode bits */
acl_type_info,
acl_aixc,
diff --git a/source3/modules/vfs_audit.c b/source3/modules/vfs_audit.c
index 91993a47d7..a63bf4f672 100644
--- a/source3/modules/vfs_audit.c
+++ b/source3/modules/vfs_audit.c
@@ -39,8 +39,8 @@ static int audit_rename(vfs_handle_struct *handle, const char *oldname, const ch
static int audit_unlink(vfs_handle_struct *handle, const char *path);
static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode);
static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode);
-static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode);
-static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode);
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
/* VFS operations */
@@ -268,11 +268,11 @@ static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t m
return result;
}
-static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n",
fsp->fsp_name, mode,
@@ -282,11 +282,11 @@ static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mo
return result;
}
-static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n",
fsp->fsp_name, mode,
diff --git a/source3/modules/vfs_cacheprime.c b/source3/modules/vfs_cacheprime.c
index 9574087d9d..be934f6bd6 100644
--- a/source3/modules/vfs_cacheprime.c
+++ b/source3/modules/vfs_cacheprime.c
@@ -48,7 +48,6 @@ static void * g_readbuf = NULL;
static bool prime_cache(
struct vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
SMB_OFF_T offset,
size_t count)
{
@@ -75,7 +74,7 @@ static bool prime_cache(
MODULE, (long long)g_readsz, (long long)*last,
fsp->fsp_name));
- nread = sys_pread(fd, g_readbuf, g_readsz, *last);
+ nread = sys_pread(fsp->fh->fd, g_readbuf, g_readsz, *last);
if (nread < 0) {
*last = -1;
return False;
@@ -125,51 +124,48 @@ static int cprime_connect(
static ssize_t cprime_sendfile(
struct vfs_handle_struct * handle,
int tofd,
- files_struct * fsp,
- int fromfd,
+ files_struct * fromfsp,
const DATA_BLOB * header,
SMB_OFF_T offset,
size_t count)
{
if (g_readbuf && offset == 0) {
- prime_cache(handle, fsp, fromfd, offset, count);
+ prime_cache(handle, fromfsp, offset, count);
}
- return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd,
+ return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp,
header, offset, count);
}
static ssize_t cprime_read(
vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
void * data,
size_t count)
{
SMB_OFF_T offset;
- offset = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+ offset = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
if (offset >= 0 && g_readbuf) {
- prime_cache(handle, fsp, fd, offset, count);
- SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET);
+ prime_cache(handle, fsp, offset, count);
+ SMB_VFS_LSEEK(fsp, offset, SEEK_SET);
}
- return SMB_VFS_NEXT_READ(handle, fsp, fd, data, count);
+ return SMB_VFS_NEXT_READ(handle, fsp, data, count);
}
static ssize_t cprime_pread(
vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
void * data,
size_t count,
SMB_OFF_T offset)
{
if (g_readbuf) {
- prime_cache(handle, fsp, fd, offset, count);
+ prime_cache(handle, fsp, offset, count);
}
- return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
}
static vfs_op_tuple cprime_ops [] =
diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c
index f99891cb32..2f2d6a7182 100644
--- a/source3/modules/vfs_cap.c
+++ b/source3/modules/vfs_cap.c
@@ -363,7 +363,7 @@ size)
return SMB_VFS_NEXT_LGETXATTR(handle, cappath, capname, value, size);
}
-static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path, void *value, size_t size)
+static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
{
char *cappath = capencode(talloc_tos(), path);
@@ -371,7 +371,7 @@ static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp
errno = ENOMEM;
return -1;
}
- return SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, cappath, value, size);
+ return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
}
static ssize_t cap_listxattr(vfs_handle_struct *handle, const char *path, char *list, size_t size)
@@ -420,7 +420,7 @@ static int cap_lremovexattr(vfs_handle_struct *handle, const char *path, const c
return SMB_VFS_NEXT_LREMOVEXATTR(handle, cappath, capname);
}
-static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path)
+static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
{
char *cappath = capencode(talloc_tos(), path);
@@ -428,7 +428,7 @@ static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp,
errno = ENOMEM;
return -1;
}
- return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, cappath);
+ return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
}
static int cap_setxattr(vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
@@ -455,7 +455,7 @@ static int cap_lsetxattr(vfs_handle_struct *handle, const char *path, const char
return SMB_VFS_NEXT_LSETXATTR(handle, cappath, capname, value, size, flags);
}
-static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *path, const void *value, size_t size, int flags)
+static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
{
char *cappath = capencode(talloc_tos(), path);
@@ -463,7 +463,7 @@ static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,int
errno = ENOMEM;
return -1;
}
- return SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, cappath, value, size, flags);
+ return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
}
/* VFS operations structure */
diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c
index 71f478a8a9..ab48c963ec 100644
--- a/source3/modules/vfs_catia.c
+++ b/source3/modules/vfs_catia.c
@@ -290,8 +290,7 @@ static NTSTATUS catia_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
const char *name, uint32 security_info,
struct security_descriptor **ppdesc)
{
- return SMB_VFS_NEXT_GET_NT_ACL(handle, fsp, name, security_info,
- ppdesc);
+ return SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc);
}
static NTSTATUS catia_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
diff --git a/source3/modules/vfs_commit.c b/source3/modules/vfs_commit.c
index d7d81924f1..ac391cf007 100644
--- a/source3/modules/vfs_commit.c
+++ b/source3/modules/vfs_commit.c
@@ -217,7 +217,7 @@ static int commit_open(
/* EOF commit modes require us to know the initial file size. */
if (c && (c->on_eof != EOF_NONE)) {
SMB_STRUCT_STAT st;
- if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) {
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
return -1;
}
c->eof = st.st_size;
@@ -229,12 +229,11 @@ static int commit_open(
static ssize_t commit_write(
vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
void * data,
size_t count)
{
ssize_t ret;
- ret = SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, count);
+ ret = SMB_VFS_NEXT_WRITE(handle, fsp, data, count);
if (ret > 0) {
if (commit(handle, fsp, fsp->fh->pos, ret) == -1) {
@@ -248,14 +247,13 @@ static ssize_t commit_write(
static ssize_t commit_pwrite(
vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
void * data,
size_t count,
SMB_OFF_T offset)
{
ssize_t ret;
- ret = SMB_VFS_NEXT_PWRITE(handle, fsp, fd, data, count, offset);
+ ret = SMB_VFS_NEXT_PWRITE(handle, fsp, data, count, offset);
if (ret > 0) {
if (commit(handle, fsp, offset, ret) == -1) {
return -1;
@@ -278,12 +276,11 @@ static int commit_close(
static int commit_ftruncate(
vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
SMB_OFF_T len)
{
int result;
- result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, len);
+ result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
if (result == 0) {
struct commit_info *c;
if ((c = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index cce5430493..cf135dfd03 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -90,6 +90,17 @@ static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path,
return sys_statvfs(path, statbuf);
}
+static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle)
+{
+#if defined(DARWINOS)
+ struct vfs_statvfs_struct statbuf;
+ ZERO_STRUCT(statbuf);
+ sys_statvfs(handle->conn->connectpath, &statbuf);
+ return statbuf.FsCapabilities;
+#endif
+ return FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+}
+
/* Directory operations */
static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
@@ -208,29 +219,29 @@ static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp, int fd)
return result;
}
-static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data, size_t n)
+static ssize_t vfswrap_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
{
ssize_t result;
START_PROFILE_BYTES(syscall_read, n);
- result = sys_read(fd, data, n);
+ result = sys_read(fsp->fh->fd, data, n);
END_PROFILE(syscall_read);
return result;
}
-static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void *data,
+static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void *data,
size_t n, SMB_OFF_T offset)
{
ssize_t result;
#if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
START_PROFILE_BYTES(syscall_pread, n);
- result = sys_pread(fd, data, n, offset);
+ result = sys_pread(fsp->fh->fd, data, n, offset);
END_PROFILE(syscall_pread);
if (result == -1 && errno == ESPIPE) {
/* Maintain the fiction that pipes can be seeked (sought?) on. */
- result = SMB_VFS_READ(fsp, fd, data, n);
+ result = SMB_VFS_READ(fsp, data, n);
fsp->fh->pos = 0;
}
@@ -238,23 +249,23 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int f
SMB_OFF_T curr;
int lerrno;
- curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+ curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
if (curr == -1 && errno == ESPIPE) {
/* Maintain the fiction that pipes can be seeked (sought?) on. */
- result = SMB_VFS_READ(fsp, fd, data, n);
+ result = SMB_VFS_READ(fsp, data, n);
fsp->fh->pos = 0;
return result;
}
- if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) {
+ if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
return -1;
}
errno = 0;
- result = SMB_VFS_READ(fsp, fd, data, n);
+ result = SMB_VFS_READ(fsp, data, n);
lerrno = errno;
- SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET);
+ SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
errno = lerrno;
#endif /* HAVE_PREAD */
@@ -262,48 +273,48 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int f
return result;
}
-static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data, size_t n)
+static ssize_t vfswrap_write(vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
{
ssize_t result;
START_PROFILE_BYTES(syscall_write, n);
- result = sys_write(fd, data, n);
+ result = sys_write(fsp->fh->fd, data, n);
END_PROFILE(syscall_write);
return result;
}
-static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int fd, const void *data,
+static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, const void *data,
size_t n, SMB_OFF_T offset)
{
ssize_t result;
#if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
START_PROFILE_BYTES(syscall_pwrite, n);
- result = sys_pwrite(fd, data, n, offset);
+ result = sys_pwrite(fsp->fh->fd, data, n, offset);
END_PROFILE(syscall_pwrite);
if (result == -1 && errno == ESPIPE) {
/* Maintain the fiction that pipes can be sought on. */
- result = SMB_VFS_WRITE(fsp, fd, data, n);
+ result = SMB_VFS_WRITE(fsp, data, n);
}
#else /* HAVE_PWRITE */
SMB_OFF_T curr;
int lerrno;
- curr = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+ curr = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
if (curr == -1) {
return -1;
}
- if (SMB_VFS_LSEEK(fsp, fd, offset, SEEK_SET) == -1) {
+ if (SMB_VFS_LSEEK(fsp, offset, SEEK_SET) == -1) {
return -1;
}
- result = SMB_VFS_WRITE(fsp, fd, data, n);
+ result = SMB_VFS_WRITE(fsp, data, n);
lerrno = errno;
- SMB_VFS_LSEEK(fsp, fd, curr, SEEK_SET);
+ SMB_VFS_LSEEK(fsp, curr, SEEK_SET);
errno = lerrno;
#endif /* HAVE_PWRITE */
@@ -311,15 +322,15 @@ static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, int
return result;
}
-static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int filedes, SMB_OFF_T offset, int whence)
+static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset, int whence)
{
SMB_OFF_T result = 0;
START_PROFILE(syscall_lseek);
/* Cope with 'stat' file opens. */
- if (filedes != -1)
- result = sys_lseek(filedes, offset, whence);
+ if (fsp->fh->fd != -1)
+ result = sys_lseek(fsp->fh->fd, offset, whence);
/*
* We want to maintain the fiction that we can seek
@@ -337,28 +348,27 @@ static SMB_OFF_T vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, int
return result;
}
-static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, int fromfd, const DATA_BLOB *hdr,
+static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
SMB_OFF_T offset, size_t n)
{
ssize_t result;
START_PROFILE_BYTES(syscall_sendfile, n);
- result = sys_sendfile(tofd, fromfd, hdr, offset, n);
+ result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
END_PROFILE(syscall_sendfile);
return result;
}
static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
int fromfd,
- files_struct *fsp,
- int tofd,
+ files_struct *tofsp,
SMB_OFF_T offset,
size_t n)
{
ssize_t result;
START_PROFILE_BYTES(syscall_recvfile, n);
- result = sys_recvfile(fromfd, tofd, offset, n);
+ result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
END_PROFILE(syscall_recvfile);
return result;
}
@@ -467,13 +477,13 @@ static int vfswrap_rename(vfs_handle_struct *handle, const char *oldname, const
return result;
}
-static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd)
+static int vfswrap_fsync(vfs_handle_struct *handle, files_struct *fsp)
{
#ifdef HAVE_FSYNC
int result;
START_PROFILE(syscall_fsync);
- result = fsync(fd);
+ result = fsync(fsp->fh->fd);
END_PROFILE(syscall_fsync);
return result;
#else
@@ -491,12 +501,12 @@ static int vfswrap_stat(vfs_handle_struct *handle, const char *fname, SMB_STRUC
return result;
}
-static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
+static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
{
int result;
START_PROFILE(syscall_fstat);
- result = sys_fstat(fd, sbuf);
+ result = sys_fstat(fsp->fh->fd, sbuf);
END_PROFILE(syscall_fstat);
return result;
}
@@ -549,7 +559,7 @@ static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mo
return result;
}
-static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
int result;
@@ -563,7 +573,7 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd,
{
int saved_errno = errno; /* We might get ENOSYS */
- if ((result = SMB_VFS_FCHMOD_ACL(fsp, fd, mode)) == 0) {
+ if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
END_PROFILE(syscall_fchmod);
return result;
}
@@ -572,7 +582,7 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd,
}
#if defined(HAVE_FCHMOD)
- result = fchmod(fd, mode);
+ result = fchmod(fsp->fh->fd, mode);
#else
result = -1;
errno = ENOSYS;
@@ -592,13 +602,13 @@ static int vfswrap_chown(vfs_handle_struct *handle, const char *path, uid_t uid,
return result;
}
-static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd, uid_t uid, gid_t gid)
+static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
{
#ifdef HAVE_FCHOWN
int result;
START_PROFILE(syscall_fchown);
- result = fchown(fd, uid, gid);
+ result = fchown(fsp->fh->fd, uid, gid);
END_PROFILE(syscall_fchown);
return result;
#else
@@ -674,17 +684,17 @@ static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const str
allocate is set.
**********************************************************************/
-static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len)
+static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len)
{
SMB_STRUCT_STAT st;
- SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+ SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
unsigned char zero_space[4096];
SMB_OFF_T space_to_write;
if (currpos == -1)
return -1;
- if (SMB_VFS_FSTAT(fsp, fd, &st) == -1)
+ if (SMB_VFS_FSTAT(fsp, &st) == -1)
return -1;
space_to_write = len - st.st_size;
@@ -699,10 +709,10 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
/* Shrink - just ftruncate. */
if (st.st_size > len)
- return sys_ftruncate(fd, len);
+ return sys_ftruncate(fsp->fh->fd, len);
/* Write out the real space on disk. */
- if (SMB_VFS_LSEEK(fsp, fd, st.st_size, SEEK_SET) != st.st_size)
+ if (SMB_VFS_LSEEK(fsp, st.st_size, SEEK_SET) != st.st_size)
return -1;
space_to_write = len - st.st_size;
@@ -712,7 +722,7 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
SMB_OFF_T retlen;
SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write);
- retlen = SMB_VFS_WRITE(fsp,fsp->fh->fd,(char *)zero_space,current_len_to_write);
+ retlen = SMB_VFS_WRITE(fsp,(char *)zero_space,current_len_to_write);
if (retlen <= 0)
return -1;
@@ -720,13 +730,13 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
}
/* Seek to where we were */
- if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos)
+ if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
return -1;
return 0;
}
-static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len)
+static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len)
{
int result = -1;
SMB_STRUCT_STAT st;
@@ -736,7 +746,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f
START_PROFILE(syscall_ftruncate);
if (lp_strict_allocate(SNUM(fsp->conn))) {
- result = strict_allocate_ftruncate(handle, fsp, fd, len);
+ result = strict_allocate_ftruncate(handle, fsp, len);
END_PROFILE(syscall_ftruncate);
return result;
}
@@ -747,14 +757,14 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f
expansion and some that don't! On Linux fat can't do
ftruncate extend but ext2 can. */
- result = sys_ftruncate(fd, len);
+ result = sys_ftruncate(fsp->fh->fd, len);
if (result == 0)
goto done;
/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
extend a file with ftruncate. Provide alternate implementation
for this */
- currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
+ currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
if (currpos == -1) {
goto done;
}
@@ -763,7 +773,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f
size in which case the ftruncate above should have
succeeded or shorter, in which case seek to len - 1 and
write 1 byte of zero */
- if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) {
+ if (SMB_VFS_FSTAT(fsp, &st) == -1) {
goto done;
}
@@ -784,14 +794,14 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f
goto done;
}
- if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1)
+ if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
goto done;
- if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1)
+ if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
goto done;
/* Seek to where we were */
- if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos)
+ if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
goto done;
result = 0;
@@ -801,36 +811,36 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int f
return result;
}
-static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
bool result;
START_PROFILE(syscall_fcntl_lock);
- result = fcntl_lock(fd, op, offset, count, type);
+ result = fcntl_lock(fsp->fh->fd, op, offset, count, type);
END_PROFILE(syscall_fcntl_lock);
return result;
}
-static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
uint32 share_mode)
{
START_PROFILE(syscall_kernel_flock);
- kernel_flock(fd, share_mode);
+ kernel_flock(fsp->fh->fd, share_mode);
END_PROFILE(syscall_kernel_flock);
return 0;
}
-static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
+static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
{
bool result;
START_PROFILE(syscall_fcntl_getlock);
- result = fcntl_getlock(fd, poffset, pcount, ptype, ppid);
+ result = fcntl_getlock(fsp->fh->fd, poffset, pcount, ptype, ppid);
END_PROFILE(syscall_fcntl_getlock);
return result;
}
-static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
int leasetype)
{
int result = -1;
@@ -839,11 +849,11 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
#ifdef HAVE_KERNEL_OPLOCKS_LINUX
/* first set the signal handler */
- if(linux_set_lease_sighandler(fd) == -1) {
+ if(linux_set_lease_sighandler(fsp->fh->fd) == -1) {
return -1;
}
- result = linux_setlease(fd, leasetype);
+ result = linux_setlease(fsp->fh->fd, leasetype);
#else
errno = ENOSYS;
#endif
@@ -943,31 +953,87 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, S
return file_id_create_dev(dev, inode);
}
+static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ unsigned int num_streams = 0;
+ struct stream_struct *streams = NULL;
+ int ret;
+
+ if ((fsp != NULL) && (fsp->is_directory)) {
+ /*
+ * No default streams on directories
+ */
+ goto done;
+ }
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ goto done;
+ }
+
+ streams = talloc(mem_ctx, struct stream_struct);
+
+ if (streams == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ streams->size = sbuf.st_size;
+ streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf);
+
+ streams->name = talloc_strdup(streams, "::$DATA");
+ if (streams->name == NULL) {
+ TALLOC_FREE(streams);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_streams = 1;
+ done:
+ *pnum_streams = num_streams;
+ *pstreams = streams;
+ return NT_STATUS_OK;
+}
+
static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp, int fd,
+ files_struct *fsp,
uint32 security_info, SEC_DESC **ppdesc)
{
NTSTATUS result;
START_PROFILE(fget_nt_acl);
- result = get_nt_acl(fsp, security_info, ppdesc);
+ result = posix_fget_nt_acl(fsp, security_info, ppdesc);
END_PROFILE(fget_nt_acl);
return result;
}
static NTSTATUS vfswrap_get_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp, const char *name,
+ const char *name,
uint32 security_info, SEC_DESC **ppdesc)
{
NTSTATUS result;
START_PROFILE(get_nt_acl);
- result = get_nt_acl(fsp, security_info, ppdesc);
+ result = posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
END_PROFILE(get_nt_acl);
return result;
}
-static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
+static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
{
NTSTATUS result;
@@ -1002,7 +1068,7 @@ static int vfswrap_chmod_acl(vfs_handle_struct *handle, const char *name, mode_
#endif
}
-static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
#ifdef HAVE_NO_ACL
errno = ENOSYS;
@@ -1011,7 +1077,7 @@ static int vfswrap_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int
int result;
START_PROFILE(fchmod_acl);
- result = fchmod_acl(fsp, fd, mode);
+ result = fchmod_acl(fsp, mode);
END_PROFILE(fchmod_acl);
return result;
#endif
@@ -1042,9 +1108,9 @@ static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, const char
return sys_acl_get_file(handle, path_p, type);
}
-static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd)
+static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp)
{
- return sys_acl_get_fd(handle, fsp, fd);
+ return sys_acl_get_fd(handle, fsp);
}
static int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset)
@@ -1097,9 +1163,9 @@ static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name
return sys_acl_set_file(handle, name, acltype, theacl);
}
-static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_ACL_T theacl)
+static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
{
- return sys_acl_set_fd(handle, fsp, fd, theacl);
+ return sys_acl_set_fd(handle, fsp, theacl);
}
static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
@@ -1141,9 +1207,9 @@ static ssize_t vfswrap_lgetxattr(struct vfs_handle_struct *handle,const char *pa
return sys_lgetxattr(path, name, value, size);
}
-static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, void *value, size_t size)
+static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
{
- return sys_fgetxattr(fd, name, value, size);
+ return sys_fgetxattr(fsp->fh->fd, name, value, size);
}
static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
@@ -1156,9 +1222,9 @@ ssize_t vfswrap_llistxattr(struct vfs_handle_struct *handle, const char *path, c
return sys_llistxattr(path, list, size);
}
-ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, char *list, size_t size)
+ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
{
- return sys_flistxattr(fd, list, size);
+ return sys_flistxattr(fsp->fh->fd, list, size);
}
static int vfswrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
@@ -1171,9 +1237,9 @@ static int vfswrap_lremovexattr(struct vfs_handle_struct *handle, const char *pa
return sys_lremovexattr(path, name);
}
-static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name)
+static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
{
- return sys_fremovexattr(fd, name);
+ return sys_fremovexattr(fsp->fh->fd, name);
}
static int vfswrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
@@ -1186,9 +1252,9 @@ static int vfswrap_lsetxattr(struct vfs_handle_struct *handle, const char *path,
return sys_lsetxattr(path, name, value, size, flags);
}
-static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp,int fd, const char *name, const void *value, size_t size, int flags)
+static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
{
- return sys_fsetxattr(fd, name, value, size, flags);
+ return sys_fsetxattr(fsp->fh->fd, name, value, size, flags);
}
static int vfswrap_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
@@ -1206,9 +1272,9 @@ static ssize_t vfswrap_aio_return(struct vfs_handle_struct *handle, struct files
return sys_aio_return(aiocb);
}
-static int vfswrap_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb)
+static int vfswrap_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
{
- return sys_aio_cancel(fd, aiocb);
+ return sys_aio_cancel(fsp->fh->fd, aiocb);
}
static int vfswrap_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
@@ -1226,6 +1292,36 @@ static int vfswrap_aio_suspend(struct vfs_handle_struct *handle, struct files_st
return sys_aio_suspend(aiocb, n, timeout);
}
+static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
+{
+ return false;
+}
+
+static bool vfswrap_is_offline(struct vfs_handle_struct *handle, const char *path, SMB_STRUCT_STAT *sbuf)
+{
+ if (ISDOT(path) || ISDOTDOT(path)) {
+ return false;
+ }
+
+ if (!lp_dmapi_support(SNUM(handle->conn)) || !dmapi_have_session()) {
+#if defined(ENOTSUP)
+ errno = ENOTSUP;
+#endif
+ return false;
+ }
+
+ return (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
+}
+
+static int vfswrap_set_offline(struct vfs_handle_struct *handle, const char *path)
+{
+ /* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
+#if defined(ENOTSUP)
+ errno = ENOTSUP;
+#endif
+ return -1;
+}
+
static vfs_op_tuple vfs_default_ops[] = {
/* Disk operations */
@@ -1244,6 +1340,8 @@ static vfs_op_tuple vfs_default_ops[] = {
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_statvfs), SMB_VFS_OP_STATVFS,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_OPAQUE},
/* Directory operations */
@@ -1338,6 +1436,8 @@ static vfs_op_tuple vfs_default_ops[] = {
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_file_id_create), SMB_VFS_OP_FILE_ID_CREATE,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
/* NT ACL operations. */
@@ -1443,6 +1543,14 @@ static vfs_op_tuple vfs_default_ops[] = {
{SMB_VFS_OP(vfswrap_aio_suspend),SMB_VFS_OP_AIO_SUSPEND,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_aio_force), SMB_VFS_OP_AIO_FORCE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(vfswrap_is_offline),SMB_VFS_OP_IS_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_set_offline),SMB_VFS_OP_SET_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+
/* Finish VFS operations definition */
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
diff --git a/source3/modules/vfs_extd_audit.c b/source3/modules/vfs_extd_audit.c
index 552c64016e..a21e281e2c 100644
--- a/source3/modules/vfs_extd_audit.c
+++ b/source3/modules/vfs_extd_audit.c
@@ -42,8 +42,8 @@ static int audit_rename(vfs_handle_struct *handle, const char *oldname, const ch
static int audit_unlink(vfs_handle_struct *handle, const char *path);
static int audit_chmod(vfs_handle_struct *handle, const char *path, mode_t mode);
static int audit_chmod_acl(vfs_handle_struct *handle, const char *name, mode_t mode);
-static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode);
-static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode);
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode);
/* VFS operations */
@@ -310,11 +310,11 @@ static int audit_chmod_acl(vfs_handle_struct *handle, const char *path, mode_t m
return result;
}
-static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
syslog(audit_syslog_priority(handle), "fchmod %s mode 0x%x %s%s\n",
fsp->fsp_name, mode,
@@ -328,11 +328,11 @@ static int audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mo
return result;
}
-static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
syslog(audit_syslog_priority(handle), "fchmod_acl %s mode 0x%x %s%s\n",
fsp->fsp_name, mode,
diff --git a/source3/modules/vfs_fake_perms.c b/source3/modules/vfs_fake_perms.c
index 8157f05d52..ddad0008a7 100644
--- a/source3/modules/vfs_fake_perms.c
+++ b/source3/modules/vfs_fake_perms.c
@@ -46,11 +46,11 @@ static int fake_perms_stat(vfs_handle_struct *handle, const char *fname, SMB_STR
return ret;
}
-static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_STRUCT_STAT *sbuf)
+static int fake_perms_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
{
int ret = -1;
- ret = SMB_VFS_NEXT_FSTAT(handle, fsp, fd, sbuf);
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
if (ret == 0) {
if (S_ISDIR(sbuf->st_mode)) {
sbuf->st_mode = S_IFDIR | S_IRWXU;
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index f4aeefbbf0..5aa9bab5b5 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -113,30 +113,30 @@ static int smb_full_audit_open(vfs_handle_struct *handle,
const char *fname, files_struct *fsp, int flags, mode_t mode);
static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp, int fd);
static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp,
- int fd, void *data, size_t n);
+ void *data, size_t n);
static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp,
- int fd, void *data, size_t n, SMB_OFF_T offset);
+ void *data, size_t n, SMB_OFF_T offset);
static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp,
- int fd, const void *data, size_t n);
+ const void *data, size_t n);
static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp,
- int fd, const void *data, size_t n,
+ const void *data, size_t n,
SMB_OFF_T offset);
static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp,
- int filedes, SMB_OFF_T offset, int whence);
+ SMB_OFF_T offset, int whence);
static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd,
- files_struct *fsp, int fromfd,
+ files_struct *fromfsp,
const DATA_BLOB *hdr, SMB_OFF_T offset,
size_t n);
static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd,
- files_struct *fsp, int tofd,
+ files_struct *tofsp,
SMB_OFF_T offset,
size_t n);
static int smb_full_audit_rename(vfs_handle_struct *handle,
const char *oldname, const char *newname);
-static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd);
+static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp);
static int smb_full_audit_stat(vfs_handle_struct *handle,
const char *fname, SMB_STRUCT_STAT *sbuf);
-static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf);
static int smb_full_audit_lstat(vfs_handle_struct *handle,
const char *path, SMB_STRUCT_STAT *sbuf);
@@ -144,11 +144,11 @@ static int smb_full_audit_unlink(vfs_handle_struct *handle,
const char *path);
static int smb_full_audit_chmod(vfs_handle_struct *handle,
const char *path, mode_t mode);
-static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp,
mode_t mode);
static int smb_full_audit_chown(vfs_handle_struct *handle,
const char *path, uid_t uid, gid_t gid);
-static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp,
uid_t uid, gid_t gid);
static int smb_full_audit_lchown(vfs_handle_struct *handle,
const char *path, uid_t uid, gid_t gid);
@@ -159,15 +159,15 @@ static char *smb_full_audit_getwd(vfs_handle_struct *handle,
static int smb_full_audit_ntimes(vfs_handle_struct *handle,
const char *path, const struct timespec ts[2]);
static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
- int fd, SMB_OFF_T len);
-static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+ SMB_OFF_T len);
+static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
uint32 share_mode);
static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
- int fd, int leasetype);
-static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+ int leasetype);
+static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp,
SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid);
static int smb_full_audit_symlink(vfs_handle_struct *handle,
const char *oldpath, const char *newpath);
@@ -191,13 +191,13 @@ static int smb_full_audit_chflags(vfs_handle_struct *handle,
static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *handle,
SMB_DEV_T dev, SMB_INO_T inode);
static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, uint32 security_info,
+ uint32 security_info,
SEC_DESC **ppdesc);
static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
const char *name, uint32 security_info,
SEC_DESC **ppdesc);
static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, uint32 security_info_sent,
+ uint32 security_info_sent,
SEC_DESC *psd);
static NTSTATUS smb_full_audit_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
const char *name, uint32 security_info_sent,
@@ -205,7 +205,7 @@ static NTSTATUS smb_full_audit_set_nt_acl(vfs_handle_struct *handle, files_struc
static int smb_full_audit_chmod_acl(vfs_handle_struct *handle,
const char *path, mode_t mode);
static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, mode_t mode);
+ mode_t mode);
static int smb_full_audit_sys_acl_get_entry(vfs_handle_struct *handle,
SMB_ACL_T theacl, int entry_id,
SMB_ACL_ENTRY_T *entry_p);
@@ -221,8 +221,7 @@ static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle,
const char *path_p,
SMB_ACL_TYPE_T type);
static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd);
+ files_struct *fsp);
static int smb_full_audit_sys_acl_clear_perms(vfs_handle_struct *handle,
SMB_ACL_PERMSET_T permset);
static int smb_full_audit_sys_acl_add_perm(vfs_handle_struct *handle,
@@ -251,7 +250,7 @@ static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle,
const char *name, SMB_ACL_TYPE_T acltype,
SMB_ACL_T theacl);
static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
- int fd, SMB_ACL_T theacl);
+ SMB_ACL_T theacl);
static int smb_full_audit_sys_acl_delete_def_file(vfs_handle_struct *handle,
const char *path);
static int smb_full_audit_sys_acl_get_perm(vfs_handle_struct *handle,
@@ -271,14 +270,14 @@ static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle,
const char *path, const char *name,
void *value, size_t size);
static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
const char *name, void *value, size_t size);
static ssize_t smb_full_audit_listxattr(struct vfs_handle_struct *handle,
const char *path, char *list, size_t size);
static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle,
const char *path, char *list, size_t size);
static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd, char *list,
+ struct files_struct *fsp, char *list,
size_t size);
static int smb_full_audit_removexattr(struct vfs_handle_struct *handle,
const char *path,
@@ -287,7 +286,7 @@ static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle,
const char *path,
const char *name);
static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
const char *name);
static int smb_full_audit_setxattr(struct vfs_handle_struct *handle,
const char *path,
@@ -298,13 +297,13 @@ static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle,
const char *name, const void *value, size_t size,
int flags);
static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd, const char *name,
+ struct files_struct *fsp, const char *name,
const void *value, size_t size, int flags);
static int smb_full_audit_aio_read(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
static int smb_full_audit_aio_write(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
-static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb);
+static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
static int smb_full_audit_aio_error(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
static int smb_full_audit_aio_fsync(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb);
static int smb_full_audit_aio_suspend(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *ts);
@@ -451,7 +450,7 @@ static vfs_op_tuple audit_op_tuples[] = {
SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
SMB_VFS_LAYER_LOGGER},
- {SMB_VFS_OP(smb_full_audit_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
+{SMB_VFS_OP(smb_full_audit_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_sys_acl_clear_perms), SMB_VFS_OP_SYS_ACL_CLEAR_PERMS,
SMB_VFS_LAYER_LOGGER},
@@ -1088,11 +1087,11 @@ static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp, in
}
static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp,
- int fd, void *data, size_t n)
+ void *data, size_t n)
{
ssize_t result;
- result = SMB_VFS_NEXT_READ(handle, fsp, fd, data, n);
+ result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
do_log(SMB_VFS_OP_READ, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1100,11 +1099,11 @@ static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp,
}
static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp,
- int fd, void *data, size_t n, SMB_OFF_T offset)
+ void *data, size_t n, SMB_OFF_T offset)
{
ssize_t result;
- result = SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, n, offset);
+ result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
do_log(SMB_VFS_OP_PREAD, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1112,11 +1111,11 @@ static ssize_t smb_full_audit_pread(vfs_handle_struct *handle, files_struct *fsp
}
static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp,
- int fd, const void *data, size_t n)
+ const void *data, size_t n)
{
ssize_t result;
- result = SMB_VFS_NEXT_WRITE(handle, fsp, fd, data, n);
+ result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
do_log(SMB_VFS_OP_WRITE, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1124,12 +1123,12 @@ static ssize_t smb_full_audit_write(vfs_handle_struct *handle, files_struct *fsp
}
static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fsp,
- int fd, const void *data, size_t n,
+ const void *data, size_t n,
SMB_OFF_T offset)
{
ssize_t result;
- result = SMB_VFS_NEXT_PWRITE(handle, fsp, fd, data, n, offset);
+ result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
do_log(SMB_VFS_OP_PWRITE, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1137,11 +1136,11 @@ static ssize_t smb_full_audit_pwrite(vfs_handle_struct *handle, files_struct *fs
}
static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *fsp,
- int filedes, SMB_OFF_T offset, int whence)
+ SMB_OFF_T offset, int whence)
{
ssize_t result;
- result = SMB_VFS_NEXT_LSEEK(handle, fsp, filedes, offset, whence);
+ result = SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
do_log(SMB_VFS_OP_LSEEK, (result != (ssize_t)-1), handle,
"%s", fsp->fsp_name);
@@ -1150,33 +1149,31 @@ static SMB_OFF_T smb_full_audit_lseek(vfs_handle_struct *handle, files_struct *f
}
static ssize_t smb_full_audit_sendfile(vfs_handle_struct *handle, int tofd,
- files_struct *fsp, int fromfd,
+ files_struct *fromfsp,
const DATA_BLOB *hdr, SMB_OFF_T offset,
size_t n)
{
ssize_t result;
- result = SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, fromfd, hdr,
- offset, n);
+ result = SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, hdr, offset, n);
do_log(SMB_VFS_OP_SENDFILE, (result >= 0), handle,
- "%s", fsp->fsp_name);
+ "%s", fromfsp->fsp_name);
return result;
}
static ssize_t smb_full_audit_recvfile(vfs_handle_struct *handle, int fromfd,
- files_struct *fsp, int tofd,
+ files_struct *tofsp,
SMB_OFF_T offset,
size_t n)
{
ssize_t result;
- result = SMB_VFS_NEXT_RECVFILE(handle, fromfd, fsp, tofd,
- offset, n);
+ result = SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n);
do_log(SMB_VFS_OP_RECVFILE, (result >= 0), handle,
- "%s", fsp->fsp_name);
+ "%s", tofsp->fsp_name);
return result;
}
@@ -1193,11 +1190,11 @@ static int smb_full_audit_rename(vfs_handle_struct *handle,
return result;
}
-static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp, int fd)
+static int smb_full_audit_fsync(vfs_handle_struct *handle, files_struct *fsp)
{
int result;
- result = SMB_VFS_NEXT_FSYNC(handle, fsp, fd);
+ result = SMB_VFS_NEXT_FSYNC(handle, fsp);
do_log(SMB_VFS_OP_FSYNC, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1216,12 +1213,12 @@ static int smb_full_audit_stat(vfs_handle_struct *handle,
return result;
}
-static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
int result;
- result = SMB_VFS_NEXT_FSTAT(handle, fsp, fd, sbuf);
+ result = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
do_log(SMB_VFS_OP_FSTAT, (result >= 0), handle, "%s", fsp->fsp_name);
@@ -1264,12 +1261,12 @@ static int smb_full_audit_chmod(vfs_handle_struct *handle,
return result;
}
-static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fchmod(vfs_handle_struct *handle, files_struct *fsp,
mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
do_log(SMB_VFS_OP_FCHMOD, (result >= 0), handle,
"%s|%o", fsp->fsp_name, mode);
@@ -1290,12 +1287,12 @@ static int smb_full_audit_chown(vfs_handle_struct *handle,
return result;
}
-static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp,
uid_t uid, gid_t gid)
{
int result;
- result = SMB_VFS_NEXT_FCHOWN(handle, fsp, fd, uid, gid);
+ result = SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
do_log(SMB_VFS_OP_FCHOWN, (result >= 0), handle, "%s|%ld|%ld",
fsp->fsp_name, (long int)uid, (long int)gid);
@@ -1353,11 +1350,11 @@ static int smb_full_audit_ntimes(vfs_handle_struct *handle,
}
static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
- int fd, SMB_OFF_T len)
+ SMB_OFF_T len)
{
int result;
- result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, len);
+ result = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, len);
do_log(SMB_VFS_OP_FTRUNCATE, (result >= 0), handle,
"%s", fsp->fsp_name);
@@ -1365,12 +1362,12 @@ static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp
return result;
}
-static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
bool result;
- result = SMB_VFS_NEXT_LOCK(handle, fsp, fd, op, offset, count, type);
+ result = SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
do_log(SMB_VFS_OP_LOCK, result, handle, "%s", fsp->fsp_name);
@@ -1378,12 +1375,12 @@ static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp, in
}
static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
uint32 share_mode)
{
int result;
- result = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, fd, share_mode);
+ result = SMB_VFS_NEXT_KERNEL_FLOCK(handle, fsp, share_mode);
do_log(SMB_VFS_OP_KERNEL_FLOCK, (result >= 0), handle, "%s",
fsp->fsp_name);
@@ -1392,11 +1389,11 @@ static int smb_full_audit_kernel_flock(struct vfs_handle_struct *handle,
}
static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
- int fd, int leasetype)
+ int leasetype)
{
int result;
- result = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, fd, leasetype);
+ result = SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
do_log(SMB_VFS_OP_LINUX_SETLEASE, (result >= 0), handle, "%s",
fsp->fsp_name);
@@ -1404,12 +1401,12 @@ static int smb_full_audit_linux_setlease(vfs_handle_struct *handle, files_struct
return result;
}
-static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, int fd,
+static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp,
SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype, pid_t *ppid)
{
bool result;
- result = SMB_VFS_NEXT_GETLOCK(handle, fsp, fd, poffset, pcount, ptype, ppid);
+ result = SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
do_log(SMB_VFS_OP_GETLOCK, result, handle, "%s", fsp->fsp_name);
@@ -1525,13 +1522,12 @@ static struct file_id smb_full_audit_file_id_create(struct vfs_handle_struct *ha
}
static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, uint32 security_info,
+ uint32 security_info,
SEC_DESC **ppdesc)
{
NTSTATUS result;
- result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, fd, security_info,
- ppdesc);
+ result = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc);
do_log(SMB_VFS_OP_FGET_NT_ACL, NT_STATUS_IS_OK(result), handle,
"%s", fsp->fsp_name);
@@ -1547,8 +1543,7 @@ static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle,
{
NTSTATUS result;
- result = SMB_VFS_NEXT_GET_NT_ACL(handle, fsp, name, security_info,
- ppdesc);
+ result = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, ppdesc);
do_log(SMB_VFS_OP_GET_NT_ACL, NT_STATUS_IS_OK(result), handle,
"%s", fsp->fsp_name);
@@ -1557,13 +1552,12 @@ static NTSTATUS smb_full_audit_get_nt_acl(vfs_handle_struct *handle,
}
static NTSTATUS smb_full_audit_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, uint32 security_info_sent,
+ uint32 security_info_sent,
SEC_DESC *psd)
{
NTSTATUS result;
- result = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, fd, security_info_sent,
- psd);
+ result = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
do_log(SMB_VFS_OP_FSET_NT_ACL, NT_STATUS_IS_OK(result), handle, "%s", fsp->fsp_name);
@@ -1598,11 +1592,11 @@ static int smb_full_audit_chmod_acl(vfs_handle_struct *handle,
}
static int smb_full_audit_fchmod_acl(vfs_handle_struct *handle, files_struct *fsp,
- int fd, mode_t mode)
+ mode_t mode)
{
int result;
- result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, fd, mode);
+ result = SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
do_log(SMB_VFS_OP_FCHMOD_ACL, (result >= 0), handle,
"%s|%o", fsp->fsp_name, mode);
@@ -1687,11 +1681,11 @@ static SMB_ACL_T smb_full_audit_sys_acl_get_file(vfs_handle_struct *handle,
}
static SMB_ACL_T smb_full_audit_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp, int fd)
+ files_struct *fsp)
{
SMB_ACL_T result;
- result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, fd);
+ result = SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp);
do_log(SMB_VFS_OP_SYS_ACL_GET_FD, (result != NULL), handle,
"%s", fsp->fsp_name);
@@ -1847,11 +1841,11 @@ static int smb_full_audit_sys_acl_set_file(vfs_handle_struct *handle,
}
static int smb_full_audit_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
int result;
- result = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, fd, theacl);
+ result = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, theacl);
do_log(SMB_VFS_OP_SYS_ACL_SET_FD, (result >= 0), handle,
"%s", fsp->fsp_name);
@@ -1960,12 +1954,12 @@ static ssize_t smb_full_audit_lgetxattr(struct vfs_handle_struct *handle,
}
static ssize_t smb_full_audit_fgetxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
const char *name, void *value, size_t size)
{
ssize_t result;
- result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, fd, name, value, size);
+ result = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
do_log(SMB_VFS_OP_FGETXATTR, (result >= 0), handle,
"%s|%s", fsp->fsp_name, name);
@@ -1998,12 +1992,12 @@ static ssize_t smb_full_audit_llistxattr(struct vfs_handle_struct *handle,
}
static ssize_t smb_full_audit_flistxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd, char *list,
+ struct files_struct *fsp, char *list,
size_t size)
{
ssize_t result;
- result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, fd, list, size);
+ result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
do_log(SMB_VFS_OP_FLISTXATTR, (result >= 0), handle,
"%s", fsp->fsp_name);
@@ -2040,12 +2034,12 @@ static int smb_full_audit_lremovexattr(struct vfs_handle_struct *handle,
}
static int smb_full_audit_fremovexattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd,
+ struct files_struct *fsp,
const char *name)
{
int result;
- result = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, fd, name);
+ result = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
do_log(SMB_VFS_OP_FREMOVEXATTR, (result >= 0), handle,
"%s|%s", fsp->fsp_name, name);
@@ -2086,13 +2080,12 @@ static int smb_full_audit_lsetxattr(struct vfs_handle_struct *handle,
}
static int smb_full_audit_fsetxattr(struct vfs_handle_struct *handle,
- struct files_struct *fsp, int fd, const char *name,
+ struct files_struct *fsp, const char *name,
const void *value, size_t size, int flags)
{
int result;
- result = SMB_VFS_NEXT_FSETXATTR(handle, fsp, fd, name, value, size,
- flags);
+ result = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
do_log(SMB_VFS_OP_FSETXATTR, (result >= 0), handle,
"%s|%s", fsp->fsp_name, name);
@@ -2133,11 +2126,11 @@ static ssize_t smb_full_audit_aio_return(struct vfs_handle_struct *handle, struc
return result;
}
-static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, int fd, SMB_STRUCT_AIOCB *aiocb)
+static int smb_full_audit_aio_cancel(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb)
{
int result;
- result = SMB_VFS_NEXT_AIO_CANCEL(handle, fsp, fd, aiocb);
+ result = SMB_VFS_NEXT_AIO_CANCEL(handle, fsp, aiocb);
do_log(SMB_VFS_OP_AIO_CANCEL, (result >= 0), handle,
"%s", fsp->fsp_name);
diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
index c207bbfe2d..d10906dfb1 100644
--- a/source3/modules/vfs_gpfs.c
+++ b/source3/modules/vfs_gpfs.c
@@ -30,10 +30,10 @@
#include <gpfs_gpl.h>
#include "nfs4_acls.h"
-
+#include "vfs_gpfs.h"
static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
- int fd, uint32 share_mode)
+ uint32 share_mode)
{
START_PROFILE(syscall_kernel_flock);
@@ -52,21 +52,21 @@ static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
}
static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp,
- int fd, int leasetype)
+ int leasetype)
{
int ret;
START_PROFILE(syscall_linux_setlease);
- if ( linux_set_lease_sighandler(fd) == -1)
+ if ( linux_set_lease_sighandler(fsp->fh->fd) == -1)
return -1;
- ret = set_gpfs_lease(fd,leasetype);
+ ret = set_gpfs_lease(fsp->fh->fd,leasetype);
if ( ret < 0 ) {
/* This must have come from GPFS not being available */
/* or some other error, hence call the default */
- ret = linux_setlease(fd, leasetype);
+ ret = linux_setlease(fsp->fh->fd, leasetype);
}
END_PROFILE(syscall_linux_setlease);
@@ -153,7 +153,7 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
/* First get the real acl length */
- gacl = gpfs_getacl_alloc(fname, GPFS_ACL_TYPE_NFS4);
+ gacl = gpfs_getacl_alloc(fname, 0);
if (gacl == NULL) {
DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
fname, strerror(errno)));
@@ -208,10 +208,10 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
- prev->aceFlags == gace->aceFlags &&
- prev->aceIFlags == gace->aceIFlags &&
- (gace->aceMask & prev->aceMask) == 0 &&
- gace->aceWho == prev->aceWho) {
+ prev->aceFlags == gace->aceFlags &&
+ prev->aceIFlags == gace->aceIFlags &&
+ (gace->aceMask & prev->aceMask) == 0 &&
+ gace->aceWho == prev->aceWho) {
/* its redundent - skip it */
continue;
}
@@ -226,8 +226,9 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
return 0;
}
-static NTSTATUS gpfsacl_get_nt_acl_common(files_struct *fsp,
- uint32 security_info, SEC_DESC **ppdesc)
+static NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp, uint32 security_info,
+ SEC_DESC **ppdesc)
{
SMB4ACL_T *pacl = NULL;
int result;
@@ -236,29 +237,37 @@ static NTSTATUS gpfsacl_get_nt_acl_common(files_struct *fsp,
result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
if (result == 0)
- return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
if (result > 0) {
DEBUG(10, ("retrying with posix acl...\n"));
- return get_nt_acl(fsp, security_info, ppdesc);
+ return posix_fget_nt_acl(fsp, security_info, ppdesc);
}
-
+
/* GPFS ACL was not read, something wrong happened, error code is set in errno */
return map_nt_error_from_unix(errno);
}
-NTSTATUS gpfsacl_fget_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp, int fd, uint32 security_info,
- SEC_DESC **ppdesc)
-{
- return gpfsacl_get_nt_acl_common(fsp, security_info, ppdesc);
-}
-
-NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp, const char *name,
+static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
+ const char *name,
uint32 security_info, SEC_DESC **ppdesc)
{
- return gpfsacl_get_nt_acl_common(fsp, security_info, ppdesc);
+ SMB4ACL_T *pacl = NULL;
+ int result;
+
+ *ppdesc = NULL;
+ result = gpfs_get_nfs4_acl(name, &pacl);
+
+ if (result == 0)
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
+
+ if (result > 0) {
+ DEBUG(10, ("retrying with posix acl...\n"));
+ return posix_get_nt_acl(handle->conn, name, security_info, ppdesc);
+ }
+
+ /* GPFS ACL was not read, something wrong happened, error code is set in errno */
+ return map_nt_error_from_unix(errno);
}
static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
@@ -292,8 +301,31 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
gace->aceType = aceprop->aceType;
gace->aceFlags = aceprop->aceFlags;
gace->aceMask = aceprop->aceMask;
+
+ /*
+ * GPFS can't distinguish between WRITE and APPEND on
+ * files, so one being set without the other is an
+ * error. Sorry for the many ()'s :-)
+ */
+
+ if (!fsp->is_directory
+ &&
+ ((((gace->aceMask & ACE4_MASK_WRITE) == 0)
+ && ((gace->aceMask & ACE4_MASK_APPEND) != 0))
+ ||
+ (((gace->aceMask & ACE4_MASK_WRITE) != 0)
+ && ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
+ &&
+ lp_parm_bool(fsp->conn->params->service, "gpfs",
+ "merge_writeappend", True)) {
+ DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
+ "WRITE^APPEND, setting WRITE|APPEND\n",
+ fsp->fsp_name));
+ gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
+ }
+
gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
-
+
if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
{
switch(aceprop->who.special_id)
@@ -338,7 +370,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i
struct gpfs_acl *acl;
NTSTATUS result = NT_STATUS_ACCESS_DENIED;
- acl = gpfs_getacl_alloc(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
+ acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
if (acl == NULL)
return result;
@@ -354,7 +386,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i
return result;
}
-static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, int fd, uint32 security_info_sent, SEC_DESC *psd)
+static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
{
return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd);
}
@@ -492,8 +524,7 @@ SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
}
@@ -607,7 +638,7 @@ int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle,
int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl);
}
@@ -620,75 +651,225 @@ int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
return -1;
}
+/*
+ * Assumed: mode bits are shiftable and standard
+ * Output: the new aceMask field for an smb nfs4 ace
+ */
+static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
+{
+ const uint32 posix_nfs4map[3] = {
+ SMB_ACE4_EXECUTE, /* execute */
+ SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
+ SMB_ACE4_READ_DATA /* read */
+ };
+ int i;
+ uint32_t posix_mask = 0x01;
+ uint32_t posix_bit;
+ uint32_t nfs4_bits;
+
+ for(i=0; i<3; i++) {
+ nfs4_bits = posix_nfs4map[i];
+ posix_bit = rwx & posix_mask;
+
+ if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
+ if (posix_bit)
+ aceMask |= nfs4_bits;
+ else
+ aceMask &= ~nfs4_bits;
+ } else {
+ /* add deny bits when suitable */
+ if (!posix_bit)
+ aceMask |= nfs4_bits;
+ else
+ aceMask &= ~nfs4_bits;
+ } /* other ace types are unexpected */
+
+ posix_mask <<= 1;
+ }
+
+ return aceMask;
+}
+
+static int gpfsacl_emu_chmod(const char *path, mode_t mode)
+{
+ SMB4ACL_T *pacl = NULL;
+ int result;
+ bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
+ int i;
+ files_struct fake_fsp; /* TODO: rationalize parametrization */
+ SMB4ACE_T *smbace;
+
+ DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
+
+ result = gpfs_get_nfs4_acl(path, &pacl);
+ if (result)
+ return result;
+
+ if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
+ DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
+ }
+
+ for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
+ SMB_ACE4PROP_T *ace = smb_get_ace4(smbace);
+ uint32_t specid = ace->who.special_id;
+
+ if (ace->flags&SMB_ACE4_ID_SPECIAL &&
+ ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
+ specid <= SMB_ACE4_WHO_EVERYONE) {
+
+ uint32_t newMask;
+
+ if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
+ haveAllowEntry[specid] = True;
+
+ /* mode >> 6 for @owner, mode >> 3 for @group,
+ * mode >> 0 for @everyone */
+ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
+ mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
+ if (ace->aceMask!=newMask) {
+ DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
+ path, ace->aceMask, newMask, specid));
+ }
+ ace->aceMask = newMask;
+ }
+ }
+
+ /* make sure we have at least ALLOW entries
+ * for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
+ * - if necessary
+ */
+ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
+ SMB_ACE4PROP_T ace;
+
+ if (haveAllowEntry[i]==True)
+ continue;
+
+ memset(&ace, 0, sizeof(SMB_ACE4PROP_T));
+ ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
+ ace.flags |= SMB_ACE4_ID_SPECIAL;
+ ace.who.special_id = i;
+
+ if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
+ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+
+ ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
+ mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
+
+ /* don't add unnecessary aces */
+ if (!ace.aceMask)
+ continue;
+
+ /* we add it to the END - as windows expects allow aces */
+ smb_add_ace4(pacl, &ace);
+ DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
+ path, mode, i, ace.aceMask));
+ }
+
+ /* don't add complementary DENY ACEs here */
+ memset(&fake_fsp, 0, sizeof(struct files_struct));
+ fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
+
+ /* put the acl */
+ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
+ return -1;
+ return 0; /* ok for [f]chmod */
+}
+
static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
{
SMB_STRUCT_STAT st;
+ int rc;
+
if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
- return -1;
+ return -1;
}
+
/* avoid chmod() if possible, to preserve acls */
if ((st.st_mode & ~S_IFMT) == mode) {
- return 0;
+ return 0;
}
- return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+
+ rc = gpfsacl_emu_chmod(path, mode);
+ if (rc == 1)
+ return SMB_VFS_NEXT_CHMOD(handle, path, mode);
+ return rc;
}
-static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, int fd, mode_t mode)
+static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
SMB_STRUCT_STAT st;
- if (SMB_VFS_NEXT_FSTAT(handle, fsp, fd, &st) != 0) {
- return -1;
+ int rc;
+
+ if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
+ return -1;
}
+
/* avoid chmod() if possible, to preserve acls */
if ((st.st_mode & ~S_IFMT) == mode) {
- return 0;
+ return 0;
}
- return SMB_VFS_NEXT_FCHMOD(handle, fsp, fd, mode);
+
+ rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
+ if (rc == 1)
+ return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+ return rc;
}
/* VFS operations structure */
static vfs_op_tuple gpfs_op_tuples[] = {
-
- { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK,
- SMB_VFS_LAYER_OPAQUE },
-
- { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE,
- SMB_VFS_LAYER_OPAQUE },
-
- { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD,
- SMB_VFS_LAYER_TRANSPARENT },
-
+
+ { SMB_VFS_OP(vfs_gpfs_kernel_flock),
+ SMB_VFS_OP_KERNEL_FLOCK,
+ SMB_VFS_LAYER_OPAQUE },
+
+ { SMB_VFS_OP(vfs_gpfs_setlease),
+ SMB_VFS_OP_LINUX_SETLEASE,
+ SMB_VFS_LAYER_OPAQUE },
+
+ { SMB_VFS_OP(gpfsacl_fget_nt_acl),
+ SMB_VFS_OP_FGET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_get_nt_acl),
+ SMB_VFS_OP_GET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_fset_nt_acl),
+ SMB_VFS_OP_FSET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_set_nt_acl),
+ SMB_VFS_OP_SET_NT_ACL,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_get_file),
+ SMB_VFS_OP_SYS_ACL_GET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_get_fd),
+ SMB_VFS_OP_SYS_ACL_GET_FD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_set_file),
+ SMB_VFS_OP_SYS_ACL_SET_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(gpfsacl_sys_acl_set_fd),
+ SMB_VFS_OP_SYS_ACL_SET_FD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
{ SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
- SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD,
- SMB_VFS_LAYER_TRANSPARENT },
-
- { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD,
- SMB_VFS_LAYER_TRANSPARENT },
+ SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(vfs_gpfs_chmod),
+ SMB_VFS_OP_CHMOD,
+ SMB_VFS_LAYER_TRANSPARENT },
+
+ { SMB_VFS_OP(vfs_gpfs_fchmod),
+ SMB_VFS_OP_FCHMOD,
+ SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }
diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h
new file mode 100644
index 0000000000..3c499b0850
--- /dev/null
+++ b/source3/modules/vfs_gpfs.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap gpfs calls in vfs functions.
+
+ Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
+
+ Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
+ and Gomati Mohanan <gomati.mohanan@in.ibm.com>
+
+ 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.
+
+
+*/
+
+bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+ uint32 share_access);
+int set_gpfs_lease(int fd, int leasetype);
+int smbd_gpfs_getacl(char *pathname, int flags, void *acl);
+int smbd_gpfs_putacl(char *pathname, int flags, void *acl);
+void init_gpfs(void);
diff --git a/source3/modules/vfs_hpuxacl.c b/source3/modules/vfs_hpuxacl.c
index edce161c19..f9293405fb 100644
--- a/source3/modules/vfs_hpuxacl.c
+++ b/source3/modules/vfs_hpuxacl.c
@@ -1,7 +1,7 @@
/*
* Unix SMB/Netbios implementation.
* VFS module to get and set HP-UX ACLs
- * Copyright (C) Michael Adam 2006
+ * Copyright (C) Michael Adam 2006,2008
*
* 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
@@ -140,7 +140,7 @@ SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle,
{
SMB_ACL_T result = NULL;
int count;
- HPUX_ACL_T hpux_acl;
+ HPUX_ACL_T hpux_acl = NULL;
DEBUG(10, ("hpuxacl_sys_acl_get_file called for file '%s'.\n",
path_p));
@@ -182,15 +182,14 @@ SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle,
* get the access ACL of a file referred to by a fd
*/
SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
/*
* HPUX doesn't have the facl call. Fake it using the path.... JRA.
*/
/* For all I see, the info should already be in the fsp
* parameter, but get it again to be safe --- necessary? */
- files_struct *file_struct_p = file_find_fd(fd);
+ files_struct *file_struct_p = file_find_fd(fsp->fh->fd);
if (file_struct_p == NULL) {
errno = EBADF;
return NULL;
@@ -214,7 +213,7 @@ int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
{
int ret = -1;
SMB_STRUCT_STAT s;
- HPUX_ACL_T hpux_acl;
+ HPUX_ACL_T hpux_acl = NULL;
int count;
DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n",
@@ -307,14 +306,14 @@ int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
*/
int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
/*
* HPUX doesn't have the facl call. Fake it using the path.... JRA.
*/
/* For all I see, the info should already be in the fsp
* parameter, but get it again to be safe --- necessary? */
- files_struct *file_struct_p = file_find_fd(fd);
+ files_struct *file_struct_p = file_find_fd(fsp->fh->fd);
if (file_struct_p == NULL) {
errno = EBADF;
return -1;
diff --git a/source3/modules/vfs_irixacl.c b/source3/modules/vfs_irixacl.c
index dab6deb747..6484e8f3eb 100644
--- a/source3/modules/vfs_irixacl.c
+++ b/source3/modules/vfs_irixacl.c
@@ -1,7 +1,7 @@
/*
Unix SMB/Netbios implementation.
VFS module to get and set irix acls
- Copyright (C) Michael Adam 2006
+ Copyright (C) Michael Adam 2006,2008
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
@@ -32,8 +32,7 @@ SMB_ACL_T irixacl_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T irixacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
errno = ENOTSUP;
return NULL;
@@ -50,7 +49,7 @@ int irixacl_sys_acl_set_file(vfs_handle_struct *handle,
int irixacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
errno = ENOTSUP;
return -1;
diff --git a/source3/modules/vfs_posixacl.c b/source3/modules/vfs_posixacl.c
index fb0c0bc8e9..21fb2ada31 100644
--- a/source3/modules/vfs_posixacl.c
+++ b/source3/modules/vfs_posixacl.c
@@ -63,11 +63,10 @@ SMB_ACL_T posixacl_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
struct smb_acl_t *result;
- acl_t acl = acl_get_fd(fd);
+ acl_t acl = acl_get_fd(fsp->fh->fd);
if (acl == NULL) {
return NULL;
@@ -114,14 +113,14 @@ int posixacl_sys_acl_set_file(vfs_handle_struct *handle,
int posixacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
int res;
acl_t acl = smb_acl_to_posix(theacl);
if (acl == NULL) {
return -1;
}
- res = acl_set_fd(fd, acl);
+ res = acl_set_fd(fsp->fh->fd, acl);
acl_free(acl);
return res;
}
diff --git a/source3/modules/vfs_prealloc.c b/source3/modules/vfs_prealloc.c
index cebf3a3933..cb3508dc30 100644
--- a/source3/modules/vfs_prealloc.c
+++ b/source3/modules/vfs_prealloc.c
@@ -47,11 +47,16 @@
#define lock_type struct flock64
#endif
+#ifdef HAVE_GPFS
+#include "gpfs_gpl.h"
+#endif
+
#define MODULE "prealloc"
static int module_debug;
static int preallocate_space(int fd, SMB_OFF_T size)
{
+#ifndef HAVE_GPFS
lock_type fl = {0};
int err;
@@ -78,6 +83,9 @@ static int preallocate_space(int fd, SMB_OFF_T size)
err = -1;
errno = ENOSYS;
#endif
+#else /* GPFS uses completely different interface */
+ err = gpfs_prealloc(fd, (gpfs_off64_t)0, (gpfs_off64_t)size);
+#endif
if (err) {
DEBUG(module_debug,
@@ -184,11 +192,10 @@ normal_open:
static int prealloc_ftruncate(vfs_handle_struct * handle,
files_struct * fsp,
- int fd,
SMB_OFF_T offset)
{
SMB_OFF_T *psize;
- int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, fd, offset);
+ int ret = SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
/* Maintain the allocated space even in the face of truncates. */
if ((psize = VFS_FETCH_FSP_EXTENSION(handle, fsp))) {
diff --git a/source3/modules/vfs_readahead.c b/source3/modules/vfs_readahead.c
index 5b663a7b26..df75814b72 100644
--- a/source3/modules/vfs_readahead.c
+++ b/source3/modules/vfs_readahead.c
@@ -17,10 +17,6 @@
#include "includes.h"
-#if !defined(HAVE_LINUX_READAHEAD) && !defined(HAVE_POSIX_FADVISE)
-static bool didmsg;
-#endif
-
struct readahead_data {
SMB_OFF_T off_bound;
SMB_OFF_T len;
@@ -39,8 +35,7 @@ struct readahead_data {
static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
int tofd,
- files_struct *fsp,
- int fromfd,
+ files_struct *fromfsp,
const DATA_BLOB *header,
SMB_OFF_T offset,
size_t count)
@@ -49,16 +44,16 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
if ( offset % rhd->off_bound == 0) {
#if defined(HAVE_LINUX_READAHEAD)
- int err = readahead(fromfd, offset, (size_t)rhd->len);
+ int err = readahead(fromfsp->fh->fd, offset, (size_t)rhd->len);
DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
- (unsigned int)fromfd,
+ (unsigned int)fromfsp->fh->fd,
(unsigned long long)offset,
(unsigned int)rhd->len,
err ));
#elif defined(HAVE_POSIX_FADVISE)
- int err = posix_fadvise(fromfd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
+ int err = posix_fadvise(fromfsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
- (unsigned int)fromfd,
+ (unsigned int)fromfsp->fh->fd,
(unsigned long long)offset,
(unsigned int)rhd->len,
err ));
@@ -71,8 +66,7 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
}
return SMB_VFS_NEXT_SENDFILE(handle,
tofd,
- fsp,
- fromfd,
+ fromfsp,
header,
offset,
count);
@@ -84,7 +78,6 @@ static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
static ssize_t readahead_pread(vfs_handle_struct *handle,
files_struct *fsp,
- int fd,
void *data,
size_t count,
SMB_OFF_T offset)
@@ -93,16 +86,16 @@ static ssize_t readahead_pread(vfs_handle_struct *handle,
if ( offset % rhd->off_bound == 0) {
#if defined(HAVE_LINUX_READAHEAD)
- int err = readahead(fd, offset, (size_t)rhd->len);
+ int err = readahead(fsp->fh->fd, offset, (size_t)rhd->len);
DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
- (unsigned int)fd,
+ (unsigned int)fsp->fh->fd,
(unsigned long long)offset,
(unsigned int)rhd->len,
err ));
#elif defined(HAVE_POSIX_FADVISE)
- int err = posix_fadvise(fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
+ int err = posix_fadvise(fsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
- (unsigned int)fd,
+ (unsigned int)fsp->fh->fd,
(unsigned long long)offset,
(unsigned int)rhd->len,
err ));
@@ -113,7 +106,7 @@ static ssize_t readahead_pread(vfs_handle_struct *handle,
}
#endif
}
- return SMB_VFS_NEXT_PREAD(handle, fsp, fd, data, count, offset);
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
}
/*******************************************************************
diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c
index fef65efa77..da1716719a 100644
--- a/source3/modules/vfs_recycle.c
+++ b/source3/modules/vfs_recycle.c
@@ -269,6 +269,7 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const char *dname)
char *token;
char *tok_str;
bool ret = False;
+ char *saveptr;
mode = recycle_directory_mode(handle);
@@ -286,7 +287,8 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const char *dname)
}
/* Create directory tree if neccessary */
- for(token = strtok(tok_str, "/"); token; token = strtok(NULL, "/")) {
+ for(token = strtok_r(tok_str, "/", &saveptr); token;
+ token = strtok_r(NULL, "/", &saveptr)) {
safe_strcat(new_dir, token, len);
if (recycle_directory_exist(handle, new_dir))
DEBUG(10, ("recycle: dir %s already exists\n", new_dir));
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
new file mode 100644
index 0000000000..ddbc5aab18
--- /dev/null
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -0,0 +1,637 @@
+/*
+ * implementation of an Shadow Copy module - version 2
+ *
+ * Copyright (C) Andrew Tridgell 2007
+ *
+ * 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"
+
+/*
+
+ This is a 2nd implemetation of a shadow copy module for exposing
+ snapshots to windows clients as shadow copies. This version has the
+ following features:
+
+ 1) you don't need to populate your shares with symlinks to the
+ snapshots. This can be very important when you have thousands of
+ shares, or use [homes]
+
+ 2) the inode number of the files is altered so it is different
+ from the original. This allows the 'restore' button to work
+ without a sharing violation
+
+ Module options:
+
+ shadow:snapdir = <directory where snapshots are kept>
+
+ This is the directory containing the @GMT-* snapshot directories. If it is an absolute
+ path it is used as-is. If it is a relative path, then it is taken relative to the mount
+ point of the filesystem that the root of this share is on
+
+ shadow:basedir = <base directory that snapshots are from>
+
+ This is an optional parameter that specifies the directory that
+ the snapshots are relative to. It defaults to the filesystem
+ mount point
+
+ shadow:fixinodes = yes/no
+
+ If you enable shadow:fixinodes then this module will modify the
+ apparent inode number of files in the snapshot directories using
+ a hash of the files path. This is needed for snapshot systems
+ where the snapshots have the same device:inode number as the
+ original files (such as happens with GPFS snapshots). If you
+ don't set this option then the 'restore' button in the shadow
+ copy UI will fail with a sharing violation.
+
+ Note that the directory names in the snapshot directory must take the form
+ @GMT-YYYY.MM.DD-HH.MM.SS
+
+ The following command would generate a correctly formatted directory name:
+ date -u +@GMT-%Y.%m.%d-%H.%M.%S
+
+ */
+
+static int vfs_shadow_copy2_debug_level = DBGC_VFS;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS vfs_shadow_copy2_debug_level
+
+#define GMT_NAME_LEN 24 /* length of a @GMT- name */
+
+/*
+ make very sure it is one of our special names
+ */
+static inline bool shadow_copy2_match_name(const char *name)
+{
+ unsigned year, month, day, hr, min, sec;
+ if (name[0] != '@') return False;
+ if (strncmp(name, "@GMT-", 5) != 0) return False;
+ if (sscanf(name, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
+ &day, &hr, &min, &sec) != 6) {
+ return False;
+ }
+ if (name[24] != 0 && name[24] != '/') {
+ return False;
+ }
+ return True;
+}
+
+/*
+ convert a name to the shadow directory
+ */
+
+#define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
+ const char *name = fname; \
+ if (shadow_copy2_match_name(fname)) { \
+ char *name2; \
+ rtype ret; \
+ name2 = convert_shadow2_name(handle, fname); \
+ if (name2 == NULL) { \
+ errno = EINVAL; \
+ return eret; \
+ } \
+ name = name2; \
+ ret = SMB_VFS_NEXT_ ## op args; \
+ talloc_free(name2); \
+ if (ret != eret) extra; \
+ return ret; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+/*
+ convert a name to the shadow directory: NTSTATUS-specific handling
+ */
+
+#define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
+ const char *name = fname; \
+ if (shadow_copy2_match_name(fname)) { \
+ char *name2; \
+ NTSTATUS ret; \
+ name2 = convert_shadow2_name(handle, fname); \
+ if (name2 == NULL) { \
+ errno = EINVAL; \
+ return eret; \
+ } \
+ name = name2; \
+ ret = SMB_VFS_NEXT_ ## op args; \
+ talloc_free(name2); \
+ if (!NT_STATUS_EQUAL(ret, eret)) extra; \
+ return ret; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+#define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
+
+#define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
+
+#define SHADOW2_NEXT2(op, args) do { \
+ if (shadow_copy2_match_name(oldname) || shadow_copy2_match_name(newname)) { \
+ errno = EROFS; \
+ return -1; \
+ } else { \
+ return SMB_VFS_NEXT_ ## op args; \
+ } \
+} while (0)
+
+
+/*
+ find the mount point of a filesystem
+ */
+static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
+ dev_t dev;
+ struct stat st;
+ char *p;
+
+ if (stat(path, &st) != 0) {
+ talloc_free(path);
+ return NULL;
+ }
+
+ dev = st.st_dev;
+
+ while ((p = strrchr(path, '/')) && p > path) {
+ *p = 0;
+ if (stat(path, &st) != 0) {
+ talloc_free(path);
+ return NULL;
+ }
+ if (st.st_dev != dev) {
+ *p = '/';
+ break;
+ }
+ }
+
+ return path;
+}
+
+/*
+ work out the location of the snapshot for this share
+ */
+static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ const char *snapdir;
+ char *mount_point;
+ const char *ret;
+
+ snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
+ if (snapdir == NULL) {
+ return NULL;
+ }
+ /* if its an absolute path, we're done */
+ if (*snapdir == '/') {
+ return snapdir;
+ }
+
+ /* other its relative to the filesystem mount point */
+ mount_point = find_mount_point(mem_ctx, handle);
+ if (mount_point == NULL) {
+ return NULL;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
+ talloc_free(mount_point);
+ return ret;
+}
+
+/*
+ work out the location of the base directory for snapshots of this share
+ */
+static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
+{
+ const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
+
+ /* other its the filesystem mount point */
+ if (basedir == NULL) {
+ basedir = find_mount_point(mem_ctx, handle);
+ }
+
+ return basedir;
+}
+
+/*
+ convert a filename from a share relative path, to a path in the
+ snapshot directory
+ */
+static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
+ const char *snapdir, *relpath, *baseoffset, *basedir;
+ size_t baselen;
+ char *ret;
+
+ snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
+ if (snapdir == NULL) {
+ DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
+ if (basedir == NULL) {
+ DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ relpath = fname + GMT_NAME_LEN;
+ baselen = strlen(basedir);
+ baseoffset = handle->conn->connectpath + baselen;
+
+ /* some sanity checks */
+ if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
+ (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
+ DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
+ basedir, handle->conn->connectpath));
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ if (*relpath == '/') relpath++;
+ if (*baseoffset == '/') baseoffset++;
+
+ ret = talloc_asprintf(handle->data, "%s/%.*s/%s/%s",
+ snapdir,
+ GMT_NAME_LEN, fname,
+ baseoffset,
+ relpath);
+ DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+/*
+ simple string hash
+ */
+static uint32 string_hash(const char *s)
+{
+ uint32 n = 0;
+ while (*s) {
+ n = ((n << 5) + n) ^ (uint32)(*s++);
+ }
+ return n;
+}
+
+/*
+ modify a sbuf return to ensure that inodes in the shadow directory
+ are different from those in the main directory
+ */
+static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
+ /* some snapshot systems, like GPFS, return the name
+ device:inode for the snapshot files as the current
+ files. That breaks the 'restore' button in the shadow copy
+ GUI, as the client gets a sharing violation.
+
+ This is a crude way of allowing both files to be
+ open at once. It has a slight chance of inode
+ number collision, but I can't see a better approach
+ without significant VFS changes
+ */
+ uint32_t shash = string_hash(fname) & 0xFF000000;
+ if (shash == 0) {
+ shash = 1;
+ }
+ sbuf->st_ino ^= shash;
+ }
+}
+
+static int shadow_copy2_rename(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(RENAME, (handle, oldname, newname));
+}
+
+static int shadow_copy2_symlink(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
+}
+
+static int shadow_copy2_link(vfs_handle_struct *handle,
+ const char *oldname, const char *newname)
+{
+ SHADOW2_NEXT2(LINK, (handle, oldname, newname));
+}
+
+static int shadow_copy2_open(vfs_handle_struct *handle,
+ const char *fname, files_struct *fsp, int flags, mode_t mode)
+{
+ SHADOW2_NEXT(OPEN, (handle, name, fsp, flags, mode), int, -1);
+}
+
+static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
+ const char *fname, const char *mask, uint32 attr)
+{
+ SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
+}
+
+static int shadow_copy2_stat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ _SHADOW2_NEXT(STAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
+}
+
+static int shadow_copy2_lstat(vfs_handle_struct *handle,
+ const char *fname, SMB_STRUCT_STAT *sbuf)
+{
+ _SHADOW2_NEXT(LSTAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
+}
+
+static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+{
+ int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name)) {
+ convert_sbuf(handle, fsp->fsp_name, sbuf);
+ }
+ return ret;
+}
+
+static int shadow_copy2_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ SHADOW2_NEXT(UNLINK, (handle, name), int, -1);
+}
+
+static int shadow_copy2_chmod(vfs_handle_struct *handle,
+ const char *fname, mode_t mode)
+{
+ SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_chown(vfs_handle_struct *handle,
+ const char *fname, uid_t uid, gid_t gid)
+{
+ SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
+}
+
+static int shadow_copy2_chdir(vfs_handle_struct *handle,
+ const char *fname)
+{
+ SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
+}
+
+static int shadow_copy2_ntimes(vfs_handle_struct *handle,
+ const char *fname, const struct timespec ts[2])
+{
+ SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1);
+}
+
+static int shadow_copy2_readlink(vfs_handle_struct *handle,
+ const char *fname, char *buf, size_t bufsiz)
+{
+ SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
+}
+
+static int shadow_copy2_mknod(vfs_handle_struct *handle,
+ const char *fname, mode_t mode, SMB_DEV_T dev)
+{
+ SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
+}
+
+static char *shadow_copy2_realpath(vfs_handle_struct *handle,
+ const char *fname, char *resolved_path)
+{
+ SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *, NULL);
+}
+
+static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
+ const char *fname, uint32 security_info,
+ struct security_descriptor **ppdesc)
+{
+ SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
+}
+
+static NTSTATUS shadow_copy2_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ const char *fname, uint32 security_info_sent,
+ struct security_descriptor *psd)
+{
+ SHADOW2_NTSTATUS_NEXT(SET_NT_ACL, (handle, fsp, name, security_info_sent, psd), NT_STATUS_ACCESS_DENIED);
+}
+
+static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode)
+{
+ SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
+{
+ SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
+}
+
+static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, int flags)
+{
+ SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
+}
+
+static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
+ const char *fname, const char *aname, void *value, size_t size)
+{
+ SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
+}
+
+static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
+ const char *fname, const char *aname, void *value, size_t size)
+{
+ SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
+}
+
+static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname,
+ char *list, size_t size)
+{
+ SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
+}
+
+static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname)
+{
+ SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
+}
+
+static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname)
+{
+ SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
+}
+
+static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname, const void *value, size_t size, int flags)
+{
+ SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
+}
+
+static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname,
+ const char *aname, const void *value, size_t size, int flags)
+{
+ SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
+}
+
+static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
+ const char *fname, mode_t mode)
+{
+ /* If the underlying VFS doesn't have ACL support... */
+ if (!handle->vfs_next.ops.chmod_acl) {
+ errno = ENOSYS;
+ return -1;
+ }
+ SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
+}
+
+static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SHADOW_COPY_DATA *shadow_copy2_data,
+ bool labels)
+{
+ SMB_STRUCT_DIR *p;
+ const char *snapdir;
+ SMB_STRUCT_DIRENT *d;
+ TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
+
+ snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
+ if (snapdir == NULL) {
+ DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
+ handle->conn->connectpath));
+ errno = EINVAL;
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
+
+ if (!p) {
+ DEBUG(0,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s' - %s\n",
+ snapdir, strerror(errno)));
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+
+ talloc_free(tmp_ctx);
+
+ shadow_copy2_data->num_volumes = 0;
+ shadow_copy2_data->labels = NULL;
+
+ while ((d = SMB_VFS_NEXT_READDIR(handle, p))) {
+ SHADOW_COPY_LABEL *tlabels;
+
+ /* ignore names not of the right form in the snapshot directory */
+ if (!shadow_copy2_match_name(d->d_name)) {
+ continue;
+ }
+
+ if (!labels) {
+ /* the caller doesn't want the labels */
+ shadow_copy2_data->num_volumes++;
+ continue;
+ }
+
+ tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
+ shadow_copy2_data->labels,
+ SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
+ if (tlabels == NULL) {
+ DEBUG(0,("shadow_copy2: out of memory\n"));
+ SMB_VFS_NEXT_CLOSEDIR(handle, p);
+ return -1;
+ }
+
+ strlcpy(tlabels[shadow_copy2_data->num_volumes], d->d_name, sizeof(*tlabels));
+ shadow_copy2_data->num_volumes++;
+ shadow_copy2_data->labels = tlabels;
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ return 0;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple shadow_copy2_ops[] = {
+ {SMB_VFS_OP(shadow_copy2_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* directory operations */
+ {SMB_VFS_OP(shadow_copy2_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* xattr and flags operations */
+ {SMB_VFS_OP(shadow_copy2_chflags), SMB_VFS_OP_CHFLAGS, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lremovexattr),SMB_VFS_OP_LREMOVEXATTR,SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* File operations */
+ {SMB_VFS_OP(shadow_copy2_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* NT File ACL operations */
+ {SMB_VFS_OP(shadow_copy2_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(shadow_copy2_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* POSIX ACL operations */
+ {SMB_VFS_OP(shadow_copy2_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
+
+ /* special shadown copy op */
+ {SMB_VFS_OP(shadow_copy2_get_shadow_copy2_data),
+ SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_shadow_copy2_init(void);
+NTSTATUS vfs_shadow_copy2_init(void)
+{
+ NTSTATUS ret;
+
+ ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2", shadow_copy2_ops);
+
+ if (!NT_STATUS_IS_OK(ret))
+ return ret;
+
+ vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
+ if (vfs_shadow_copy2_debug_level == -1) {
+ vfs_shadow_copy2_debug_level = DBGC_VFS;
+ DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
+ "vfs_shadow_copy2_init"));
+ } else {
+ DEBUG(10, ("%s: Debug class number of '%s': %d\n",
+ "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
+ }
+
+ return ret;
+}
diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c
index 673b6805af..7bdfe8465b 100644
--- a/source3/modules/vfs_solarisacl.c
+++ b/source3/modules/vfs_solarisacl.c
@@ -1,7 +1,7 @@
/*
Unix SMB/Netbios implementation.
VFS module to get and set Solaris ACLs
- Copyright (C) Michael Adam 2006
+ Copyright (C) Michael Adam 2006,2008
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
@@ -100,8 +100,7 @@ SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle,
* get the access ACL of a file referred to by a fd
*/
SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
SMB_ACL_T result = NULL;
int count;
@@ -109,7 +108,7 @@ SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle,
DEBUG(10, ("entering solarisacl_sys_acl_get_fd.\n"));
- if (!solaris_acl_get_fd(fd, &solaris_acl, &count)) {
+ if (!solaris_acl_get_fd(fsp->fh->fd, &solaris_acl, &count)) {
goto done;
}
/*
@@ -219,7 +218,7 @@ int solarisacl_sys_acl_set_file(vfs_handle_struct *handle,
*/
int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
SOLARIS_ACL_T solaris_acl = NULL;
SOLARIS_ACL_T default_acl = NULL;
@@ -242,7 +241,7 @@ int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle,
strerror(errno)));
goto done;
}
- if (!solaris_acl_get_fd(fd, &default_acl, &default_count)) {
+ if (!solaris_acl_get_fd(fsp->fh->fd, &default_acl, &default_count)) {
DEBUG(10, ("error getting (default) acl from fd\n"));
goto done;
}
@@ -258,14 +257,14 @@ int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle,
goto done;
}
- ret = facl(fd, SETACL, count, solaris_acl);
+ ret = facl(fsp->fh->fd, SETACL, count, solaris_acl);
if (ret != 0) {
DEBUG(10, ("call of facl failed (%s).\n", strerror(errno)));
}
done:
- DEBUG(10, ("solarisacl_sys_acl_st_fd %s.\n",
- ((ret == 0) ? "succeded" : "failed" )));
+ DEBUG(10, ("solarisacl_sys_acl_set_fd %s.\n",
+ ((ret == 0) ? "succeeded" : "failed" )));
SAFE_FREE(solaris_acl);
SAFE_FREE(default_acl);
return ret;
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
new file mode 100644
index 0000000000..fa85ea4a57
--- /dev/null
+++ b/source3/modules/vfs_streams_depot.c
@@ -0,0 +1,641 @@
+/*
+ * Store streams in a separate subdirectory
+ *
+ * Copyright (C) Volker Lendecke, 2007
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * Excerpt from a mail from tridge:
+ *
+ * Volker, what I'm thinking of is this:
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
+ *
+ * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
+ * is the fsid/inode. "namedstreamX" is a file named after the stream
+ * name.
+ */
+
+static uint32_t hash_fn(DATA_BLOB key)
+{
+ uint32_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
+ value = (value + (key.data[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/*
+ * With the hashing scheme based on the inode we need to protect against
+ * streams showing up on files with re-used inodes. This can happen if we
+ * create a stream directory from within Samba, and a local process or NFS
+ * client deletes the file without deleting the streams directory. When the
+ * inode is re-used and the stream directory is still around, the streams in
+ * there would be show up as belonging to the new file.
+ *
+ * There are several workarounds for this, probably the easiest one is on
+ * systems which have a true birthtime stat element: When the file has a later
+ * birthtime than the streams directory, then we have to recreate the
+ * directory.
+ *
+ * The other workaround is to somehow mark the file as generated by Samba with
+ * something that a NFS client would not do. The closest one is a special
+ * xattr value being set. On systems which do not support xattrs, it might be
+ * an option to put in a special ACL entry for a non-existing group.
+ */
+
+#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
+
+static bool file_is_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf;
+
+ DEBUG(10, ("file_is_valid (%s) called\n", path));
+
+ if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf)) != sizeof(buf)) {
+ DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ if (buf != '1') {
+ DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
+ return false;
+ }
+
+ return true;
+}
+
+static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf = '1';
+ int ret;
+
+ DEBUG(10, ("marking file %s as valid\n", path));
+
+ ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf), 0);
+
+ if (ret == -1) {
+ DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ return true;
+}
+
+static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
+ const SMB_STRUCT_STAT *base_sbuf, bool create_it)
+{
+ uint32_t hash;
+ char *result = NULL;
+ SMB_STRUCT_STAT sbuf;
+ uint8_t first, second;
+ char *tmp;
+ char *id_hex;
+ struct file_id id;
+ uint8 id_buf[16];
+
+ const char *rootdir = lp_parm_const_string(
+ SNUM(handle->conn), "streams", "directory",
+ handle->conn->connectpath);
+
+ if (base_sbuf == NULL) {
+ if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) {
+ /*
+ * base file is not there
+ */
+ goto fail;
+ }
+ base_sbuf = &sbuf;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev,
+ base_sbuf->st_ino);
+
+ push_file_id_16((char *)id_buf, &id);
+
+ hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
+
+ first = hash & 0xff;
+ second = (hash >> 8) & 0xff;
+
+ id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf));
+
+ if (id_hex == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
+ first, second, id_hex);
+
+ TALLOC_FREE(id_hex);
+
+ if (result == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) {
+ char *newname;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (file_is_valid(handle, base_path)) {
+ return result;
+ }
+
+ /*
+ * Someone has recreated a file under an existing inode
+ * without deleting the streams directory. For now, just move
+ * it away.
+ */
+
+ again:
+ newname = talloc_asprintf(talloc_tos(), "lost-%lu", random());
+ if (newname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if (SMB_VFS_NEXT_RENAME(handle, result, newname) == -1) {
+ if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
+ TALLOC_FREE(newname);
+ goto again;
+ }
+ goto fail;
+ }
+
+ TALLOC_FREE(newname);
+ }
+
+ if (!create_it) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
+ second);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ if (!mark_file_valid(handle, base_path)) {
+ goto fail;
+ }
+
+ return result;
+
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static char *stream_name(vfs_handle_struct *handle, const char *fname,
+ bool create_dir)
+{
+ char *base = NULL;
+ char *sname = NULL;
+ char *id_hex = NULL;
+ char *dirname, *stream_fname;
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname))) {
+ DEBUG(10, ("split_ntfs_stream_name failed\n"));
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ dirname = stream_dir(handle, base, NULL, create_dir);
+
+ if (dirname == NULL) {
+ goto fail;
+ }
+
+ stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname);
+
+ if (stream_fname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(10, ("stream filename = %s\n", stream_fname));
+
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+
+ return stream_fname;
+
+ fail:
+ DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+ return NULL;
+}
+
+static NTSTATUS walk_streams(vfs_handle_struct *handle,
+ const char *fname,
+ const SMB_STRUCT_STAT *sbuf,
+ char **pdirname,
+ bool (*fn)(const char *dirname,
+ const char *dirent,
+ void *private_data),
+ void *private_data)
+{
+ char *dirname;
+ SMB_STRUCT_DIR *dirhandle = NULL;
+ char *dirent;
+
+ dirname = stream_dir(handle, fname, sbuf, false);
+
+ if (dirname == NULL) {
+ if (errno == ENOENT) {
+ /*
+ * no stream around
+ */
+ return NT_STATUS_OK;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
+
+ dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0);
+
+ if (dirhandle == NULL) {
+ TALLOC_FREE(dirname);
+ return map_nt_error_from_unix(errno);
+ }
+
+ while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) {
+
+ if (ISDOT(dirent) || ISDOTDOT(dirent)) {
+ continue;
+ }
+
+ DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
+
+ if (!fn(dirname, dirent, private_data)) {
+ break;
+ }
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
+
+ if (pdirname != NULL) {
+ *pdirname = dirname;
+ }
+ else {
+ TALLOC_FREE(dirname);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static int streams_depot_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ DEBUG(10, ("streams_depot_stat called for [%s]\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ char *base = NULL;
+ SMB_STRUCT_STAT base_sbuf;
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, NULL))) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf);
+
+ if (ret == -1) {
+ goto done;
+ }
+
+ TALLOC_FREE(base);
+
+ stream_fname = stream_name(handle, fname, true);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_OPEN(handle, stream_fname, fsp, flags, mode);
+
+ done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ int ret = -1;
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("streams_depot_unlink called for %s\n", fname));
+
+ if (is_ntfs_stream_name(fname)) {
+ char *stream_fname;
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, stream_fname);
+
+ TALLOC_FREE(stream_fname);
+ return ret;
+ }
+
+ /*
+ * We potentially need to delete the per-inode streams directory
+ */
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) {
+ return -1;
+ }
+
+ if (sbuf.st_nlink == 1) {
+ char *dirname = stream_dir(handle, fname, &sbuf, false);
+
+ if (dirname != NULL) {
+ SMB_VFS_NEXT_RMDIR(handle, dirname);
+ }
+ TALLOC_FREE(dirname);
+ }
+
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(const char *dirname,
+ const char *dirent,
+ void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+ char *full_sname;
+ SMB_STRUCT_STAT sbuf;
+
+ if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+ if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) {
+ DEBUG(10, ("Could not stat %s: %s\n", full_sname,
+ strerror(errno)));
+ SAFE_FREE(full_sname);
+ return true;
+ }
+
+ SAFE_FREE(full_sname);
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ dirent, sbuf.st_size,
+ get_allocation_size(
+ state->handle->conn, NULL, &sbuf))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream,
+ &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_depot_ops[] = {
+ {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_depot_init(void);
+NTSTATUS vfs_streams_depot_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
+ streams_depot_ops);
+}
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
new file mode 100644
index 0000000000..766e7d10ab
--- /dev/null
+++ b/source3/modules/vfs_streams_xattr.c
@@ -0,0 +1,685 @@
+/*
+ * Store streams in xattrs
+ *
+ * Copyright (C) Volker Lendecke, 2008
+ *
+ * Partly based on James Peach's Darwin module, which is
+ *
+ * Copyright (C) James Peach 2006-2007
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+struct stream_io {
+ char *base;
+ char *xattr_name;
+};
+
+static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
+{
+ struct MD5Context ctx;
+ unsigned char hash[16];
+ SMB_INO_T result;
+ char *upper_sname;
+
+ DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
+ (unsigned long)sbuf->st_dev,
+ (unsigned long)sbuf->st_ino, sname));
+
+ upper_sname = talloc_strdup_upper(talloc_tos(), sname);
+ SMB_ASSERT(upper_sname != NULL);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_dev),
+ sizeof(sbuf->st_dev));
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_ino),
+ sizeof(sbuf->st_ino));
+ MD5Update(&ctx, (unsigned char *)upper_sname,
+ talloc_get_size(upper_sname)-1);
+ MD5Final(hash, &ctx);
+
+ TALLOC_FREE(upper_sname);
+
+ /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
+ memcpy(&result, hash, sizeof(result));
+
+ DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
+
+ return result;
+}
+
+static ssize_t get_xattr_size(connection_struct *conn, const char *fname,
+ const char *xattr_name)
+{
+ NTSTATUS status;
+ struct ea_struct ea;
+ ssize_t result;
+
+ status = get_ea_value(talloc_tos(), conn, NULL, fname,
+ xattr_name, &ea);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ result = ea.value.length-1;
+ TALLOC_FREE(ea.value.data);
+ return result;
+}
+
+
+static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ struct stream_io *io = (struct stream_io *)
+ VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
+
+ if (io == NULL) {
+ return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ }
+
+ if (SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) == -1) {
+ return -1;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, io->base, io->xattr_name);
+ if (sbuf->st_size == -1) {
+ return -1;
+ }
+
+ DEBUG(10, ("sbuf->st_size = %d\n", (int)sbuf->st_size));
+
+ sbuf->st_ino = stream_inode(sbuf, io->xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ return 0;
+}
+
+static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base = NULL, *sname = NULL;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base, *sname;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ NTSTATUS status;
+ struct stream_io *sio;
+ char *base, *sname;
+ struct ea_struct ea;
+ char *xattr_name;
+ int baseflags;
+ int hostfd = -1;
+
+ DEBUG(10, ("streams_xattr_open called for %s\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ status = split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ /*
+ * We use baseflags to turn off nasty side-effects when opening the
+ * underlying file.
+ */
+ baseflags = flags;
+ baseflags &= ~O_TRUNC;
+ baseflags &= ~O_EXCL;
+ baseflags &= ~O_CREAT;
+
+ hostfd = SMB_VFS_OPEN(handle->conn, base, fsp, baseflags, mode);
+
+ /* It is legit to open a stream on a directory, but the base
+ * fd has to be read-only.
+ */
+ if ((hostfd == -1) && (errno == EISDIR)) {
+ baseflags &= ~O_ACCMODE;
+ baseflags |= O_RDONLY;
+ hostfd = SMB_VFS_OPEN(handle->conn, fname, fsp, baseflags,
+ mode);
+ }
+
+ if (hostfd == -1) {
+ goto fail;
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, NULL, base,
+ xattr_name, &ea);
+
+ DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ /*
+ * The base file is not there. This is an error even if we got
+ * O_CREAT, the higher levels should have created the base
+ * file for us.
+ */
+ DEBUG(10, ("streams_xattr_open: base file %s not around, "
+ "returning ENOENT\n", base));
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * The attribute does not exist
+ */
+
+ if (flags & O_CREAT) {
+ /*
+ * Darn, xattrs need at least 1 byte
+ */
+ char null = '\0';
+
+ DEBUG(10, ("creating attribute %s on file %s\n",
+ xattr_name, base));
+
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+ }
+
+ if (flags & O_TRUNC) {
+ char null = '\0';
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+
+ sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
+ struct stream_io);
+ if (sio == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ xattr_name);
+ sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ base);
+
+ if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ TALLOC_FREE(frame);
+ return hostfd;
+
+ fail:
+ if (hostfd >= 0) {
+ /*
+ * BUGBUGBUG -- we would need to call fd_close_posix here, but
+ * we don't have a full fsp yet
+ */
+ SMB_VFS_CLOSE(fsp, hostfd);
+ }
+
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *sname = NULL;
+ int ret = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name);
+
+ if ((ret == -1) && (errno == ENOATTR)) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ ret = 0;
+
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return ret;
+}
+
+static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
+ const char *fname,
+ bool (*fn)(struct ea_struct *ea,
+ void *private_data),
+ void *private_data)
+{
+ NTSTATUS status;
+ char **names;
+ size_t i, num_names;
+ size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
+
+ status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ &names, &num_names);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i=0; i<num_names; i++) {
+ struct ea_struct ea;
+
+ if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
+ prefix_len) != 0) {
+ continue;
+ }
+
+ status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not get ea %s for file %s: %s\n",
+ names[i], fname, nt_errstr(status)));
+ continue;
+ }
+
+ ea.name = talloc_asprintf(ea.value.data, ":%s",
+ names[i] + prefix_len);
+ if (ea.name == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continue;
+ }
+
+ if (!fn(&ea, private_data)) {
+ TALLOC_FREE(ea.value.data);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(ea.value.data);
+ }
+
+ TALLOC_FREE(names);
+ return NT_STATUS_OK;
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(struct ea_struct *ea, void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ ea->name, ea->value.length-1,
+ smb_roundup(state->handle->conn,
+ ea->value.length-1))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_xattr_streams(handle->conn, fsp, fname,
+ collect_one_stream, &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp, const void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ int ret;
+
+ DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ if ((offset + n) > ea.value.length-1) {
+ uint8 *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+ offset + n + 1);
+
+ if (tmp == NULL) {
+ TALLOC_FREE(ea.value.data);
+ errno = ENOMEM;
+ return -1;
+ }
+ ea.value.data = tmp;
+ ea.value.length = offset + n + 1;
+ ea.value.data[offset+n] = 0;
+ }
+
+ memcpy(ea.value.data + offset, data, n);
+
+ ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+
+ TALLOC_FREE(ea.value.data);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ return n;
+}
+
+static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
+ files_struct *fsp, void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ size_t length, overlap;
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ length = ea.value.length-1;
+
+ /* Attempt to read past EOF. */
+ if (length <= offset) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ overlap = (offset + n) > length ? (length - offset) : n;
+ memcpy(data, ea.value.data + offset, overlap);
+
+ TALLOC_FREE(ea.value.data);
+ return overlap;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_xattr_ops[] = {
+ {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_xattr_init(void);
+NTSTATUS vfs_streams_xattr_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
+ streams_xattr_ops);
+}
diff --git a/source3/modules/vfs_tru64acl.c b/source3/modules/vfs_tru64acl.c
index 43cae0f826..b23a7ddcfa 100644
--- a/source3/modules/vfs_tru64acl.c
+++ b/source3/modules/vfs_tru64acl.c
@@ -1,7 +1,7 @@
/*
Unix SMB/Netbios implementation.
VFS module to get and set Tru64 acls
- Copyright (C) Michael Adam 2006
+ Copyright (C) Michael Adam 2006,2008
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
@@ -67,11 +67,10 @@ SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle,
}
SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle,
- files_struct *fsp,
- int fd)
+ files_struct *fsp)
{
struct smb_acl_t *result;
- acl_t tru64_acl = acl_get_fd(fd, ACL_TYPE_ACCESS);
+ acl_t tru64_acl = acl_get_fd(fsp->fh->fd, ACL_TYPE_ACCESS);
if (tru64_acl == NULL) {
return NULL;
@@ -129,14 +128,14 @@ fail:
int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, SMB_ACL_T theacl)
+ SMB_ACL_T theacl)
{
int res;
acl_t tru64_acl = smb_acl_to_tru64_acl(theacl);
if (tru64_acl == NULL) {
return -1;
}
- res = acl_set_fd(fd, ACL_TYPE_ACCESS, tru64_acl);
+ res = acl_set_fd(fsp->fh->fd, ACL_TYPE_ACCESS, tru64_acl);
acl_free(tru64_acl);
return res;
diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
new file mode 100644
index 0000000000..2805488e8b
--- /dev/null
+++ b/source3/modules/vfs_tsmsm.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba VFS module for handling offline files
+ with Tivoli Storage Manager Space Management
+
+ (c) Alexander Bokovoy, 2007
+ (c) Andrew Tridgell, 2007
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+/*
+ This VFS module accepts following options:
+ tsmsm: hsm script = <path to hsm script> (/bin/true by default, i.e. does nothing)
+ hsm script should point to a shell script which accepts two arguments:
+ <operation> <filepath>
+ where <operation> is currently 'offline' to set offline status of the <filepath>
+
+ tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default)
+
+ The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics
+ based on the fact that number of blocks reported of a file multiplied by 512 will be
+ bigger than 'online ratio' of actual size for online (non-migrated) files.
+
+ If checks fail, we call DMAPI and ask for specific IBM attribute which present for
+ offline (migrated) files. If this attribute presents, we consider file offline.
+ */
+
+#include "includes.h"
+
+#ifndef USE_DMAPI
+#error "This module requires DMAPI support!"
+#endif
+
+#ifdef HAVE_XFS_DMAPI_H
+#include <xfs/dmapi.h>
+#elif defined(HAVE_SYS_DMI_H)
+#include <sys/dmi.h>
+#elif defined(HAVE_SYS_JFSDMAPI_H)
+#include <sys/jfsdmapi.h>
+#elif defined(HAVE_SYS_DMAPI_H)
+#include <sys/dmapi.h>
+#elif defined(HAVE_DMAPI_H)
+#include <dmapi.h>
+#endif
+
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE
+#endif
+
+#include <math.h>
+
+/* optimisation tunables - used to avoid the DMAPI slow path */
+#define FILE_IS_ONLINE_RATIO 0.5
+#define DM_ATTRIB_OBJECT "IBMObj"
+#define DM_ATTRIB_MIGRATED "IBMMig"
+
+struct tsmsm_struct {
+ dm_sessid_t sid;
+ float online_ratio;
+ char *hsmscript;
+};
+
+#define TSM_STRINGIFY(a) #a
+#define TSM_TOSTRING(a) TSM_STRINGIFY(a)
+
+static void tsmsm_free_data(void **pptr) {
+ struct tsmsm_struct **tsmd = (struct tsmsm_struct **)pptr;
+ if(!tsmd) return;
+ TALLOC_FREE(*tsmd);
+}
+
+static int tsmsm_connect(struct vfs_handle_struct *handle,
+ const char *service,
+ const char *user) {
+ struct tsmsm_struct *tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct);
+ const char *hsmscript, *tsmname;
+ const char *fres;
+
+ if (!tsmd) {
+ DEBUG(0,("tsmsm_connect: out of memory!\n"));
+ return -1;
+ }
+
+ tsmd->sid = *(dm_sessid_t*) dmapi_get_current_session();
+
+ if (tsmd->sid == DM_NO_SESSION) {
+ DEBUG(0,("tsmsm_connect: no DMAPI session for Samba is available!\n"));
+ TALLOC_FREE(tsmd);
+ return -1;
+ }
+
+ tsmname = (handle->param ? handle->param : "tsmsm");
+ hsmscript = lp_parm_const_string(SNUM(handle->conn), tsmname,
+ "hsm script", NULL);
+ if (hsmscript) {
+ tsmd->hsmscript = talloc_strdup(tsmd, hsmscript);
+ if(!tsmd->hsmscript) {
+ DEBUG(1, ("tsmsm_connect: can't allocate memory for hsm script path"));
+ TALLOC_FREE(tsmd);
+ return -1;
+ }
+ } else {
+ DEBUG(1, ("tsmsm_connect: can't call hsm script because it "
+ "is not set to anything in the smb.conf\n"
+ "Use %s: 'hsm script = path' to set it\n",
+ tsmname));
+ TALLOC_FREE(tsmd);
+ return -1;
+ }
+
+ fres = lp_parm_const_string(SNUM(handle->conn), tsmname,
+ "online ratio", TSM_TOSTRING(FILE_IS_ONLINE_RATIO));
+ tsmd->online_ratio = strtof(fres, NULL);
+ if((tsmd->online_ratio == (float)0) || ((errno == ERANGE) &&
+ ((tsmd->online_ratio == HUGE_VALF) ||
+ (tsmd->online_ratio == HUGE_VALL)))) {
+ DEBUG(1, ("tsmsm_connect: error while getting online ratio from smb.conf."
+ "Default to %s.\n", TSM_TOSTRING(FILE_IS_ONLINE_RATIO)));
+ tsmd->online_ratio = FILE_IS_ONLINE_RATIO;
+ }
+
+ /* Store the private data. */
+ SMB_VFS_HANDLE_SET_DATA(handle, tsmd, tsmsm_free_data,
+ struct tsmsm_struct, return -1);
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
+ const char *path,
+ SMB_STRUCT_STAT *stbuf) {
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ void *dmhandle = NULL;
+ size_t dmhandle_len = 0;
+ size_t rlen;
+ dm_attrname_t dmname;
+ int ret;
+ bool offline;
+
+ /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
+ then assume it is not offline (it may not be 100%, as it could be sparse) */
+ if (512 * (off_t)stbuf->st_blocks >= stbuf->st_size * tsmd->online_ratio) {
+ DEBUG(10,("%s not offline: st_blocks=%ld st_size=%ld online_ratio=%.2f\n",
+ path, stbuf->st_blocks, stbuf->st_size, tsmd->online_ratio));
+ return false;
+ }
+
+ /* using POSIX capabilities does not work here. It's a slow path, so
+ * become_root() is just as good anyway (tridge)
+ */
+
+ /* Also, AIX has DMAPI but no POSIX capablities support. In this case,
+ * we need to be root to do DMAPI manipulations.
+ */
+ become_root();
+
+ /* go the slow DMAPI route */
+ if (dm_path_to_handle((char*)path, &dmhandle, &dmhandle_len) != 0) {
+ DEBUG(2,("dm_path_to_handle failed - assuming offline (%s) - %s\n",
+ path, strerror(errno)));
+ offline = true;
+ goto done;
+ }
+
+ memset(&dmname, 0, sizeof(dmname));
+ strlcpy((char *)&dmname.an_chars[0], DM_ATTRIB_OBJECT, sizeof(dmname.an_chars));
+
+ ret = dm_get_dmattr(tsmd->sid, dmhandle, dmhandle_len,
+ DM_NO_TOKEN, &dmname, 0, NULL, &rlen);
+
+ /* its offline if the IBMObj attribute exists */
+ offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+
+ DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno)));
+
+ ret = 0;
+
+ dm_handle_free(dmhandle, dmhandle_len);
+
+done:
+ unbecome_root();
+ return offline;
+}
+
+
+static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ /* see if the file might be offline. This is called before each IO
+ to ensure we use AIO if the file is offline. We don't do the full dmapi
+ call as that would be too slow, instead we err on the side of using AIO
+ if the file might be offline
+ */
+ if(SMB_VFS_FSTAT(fsp, &sbuf) == 0) {
+ DEBUG(10,("tsmsm_aio_force st_blocks=%ld st_size=%ld online_ratio=%.2f\n",
+ sbuf.st_blocks, sbuf.st_size, tsmd->online_ratio));
+ return !(512 * (off_t)sbuf.st_blocks >= sbuf.st_size * tsmd->online_ratio);
+ }
+ return false;
+}
+
+static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ SMB_STRUCT_AIOCB *aiocb)
+{
+ ssize_t result;
+
+ result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
+ if(result >= 0) {
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
+ SMB_OFF_T offset, size_t n)
+{
+ bool file_online = tsmsm_aio_force(handle, fsp);
+
+ if(!file_online)
+ return ENOSYS;
+
+ return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
+}
+
+/* We do overload pread to allow notification when file becomes online after offline status */
+/* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */
+static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset) {
+ ssize_t result;
+ bool notify_online = tsmsm_aio_force(handle, fsp);
+
+ result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ if((result != -1) && notify_online) {
+ /* We can't actually force AIO at this point (came here not from reply_read_and_X)
+ what we can do is to send notification that file became online
+ */
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp,
+ void *data, size_t n, SMB_OFF_T offset) {
+ ssize_t result;
+ bool notify_online = tsmsm_aio_force(handle, fsp);
+
+ result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ if((result != -1) && notify_online) {
+ /* We can't actually force AIO at this point (came here not from reply_read_and_X)
+ what we can do is to send notification that file became online
+ */
+ notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ fsp->fsp_name);
+ }
+
+ return result;
+}
+
+static int tsmsm_set_offline(struct vfs_handle_struct *handle,
+ const char *path) {
+ struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
+ int result = 0;
+ char *command;
+
+ /* Now, call the script */
+ command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path);
+ if(!command) {
+ DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script"));
+ return -1;
+ }
+ DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command));
+ if((result = smbrun(command, NULL)) != 0) {
+ DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result));
+ }
+ TALLOC_FREE(command);
+ return result;
+}
+
+static bool tsmsm_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
+{
+ bool result;
+
+ result = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
+ statbuf->FsCapabilities | = FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS;
+
+ return result;
+}
+
+static vfs_op_tuple vfs_tsmsm_ops[] = {
+
+ /* Disk operations */
+
+ {SMB_VFS_OP(tsmsm_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_statvfs), SMB_VFS_OP_STATVFS,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_aio_force), SMB_VFS_OP_AIO_FORCE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_aio_return), SMB_VFS_OP_AIO_RETURN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_sendfile), SMB_VFS_OP_SENDFILE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(tsmsm_is_offline), SMB_VFS_OP_IS_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(tsmsm_set_offline), SMB_VFS_OP_SET_OFFLINE,
+ SMB_VFS_LAYER_OPAQUE},
+
+ /* Finish VFS operations definition */
+
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
+ SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_tsmsm_init(void);
+NTSTATUS vfs_tsmsm_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "tsmsm", vfs_tsmsm_ops);
+}
diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c
new file mode 100644
index 0000000000..171022b01b
--- /dev/null
+++ b/source3/modules/vfs_xattr_tdb.c
@@ -0,0 +1,755 @@
+/*
+ * Store posix-level xattrs in a tdb
+ *
+ * Copyright (C) Volker Lendecke, 2007
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "librpc/gen_ndr/xattr.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * unmarshall tdb_xattrs
+ */
+
+static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx,
+ const TDB_DATA *data,
+ struct tdb_xattrs **presult)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct tdb_xattrs *result;
+
+ if (!(result = TALLOC_ZERO_P(mem_ctx, struct tdb_xattrs))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (data->dsize == 0) {
+ *presult = result;
+ return NT_STATUS_OK;
+ }
+
+ blob = data_blob_const(data->dptr, data->dsize);
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_tdb_xattrs failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+/*
+ * marshall tdb_xattrs
+ */
+
+static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx,
+ const struct tdb_xattrs *attribs,
+ TDB_DATA *data)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, attribs,
+ (ndr_push_flags_fn_t)ndr_push_tdb_xattrs);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_tdb_xattrs failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);;
+ }
+
+ *data = make_tdb_data(blob.data, blob.length);
+ return NT_STATUS_OK;
+}
+
+/*
+ * Load tdb_xattrs for a file from the tdb
+ */
+
+static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
+ struct db_context *db_ctx,
+ const struct file_id *id,
+ struct tdb_xattrs **presult)
+{
+ uint8 id_buf[16];
+ NTSTATUS status;
+ TDB_DATA data;
+
+ push_file_id_16((char *)id_buf, id);
+
+ if (db_ctx->fetch(db_ctx, mem_ctx,
+ make_tdb_data(id_buf, sizeof(id_buf)),
+ &data) == -1) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
+ TALLOC_FREE(data.dptr);
+ return status;
+}
+
+/*
+ * fetch_lock the tdb_ea record for a file
+ */
+
+static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
+ struct db_context *db_ctx,
+ const struct file_id *id)
+{
+ uint8 id_buf[16];
+ push_file_id_16((char *)id_buf, id);
+ return db_ctx->fetch_locked(db_ctx, mem_ctx,
+ make_tdb_data(id_buf, sizeof(id_buf)));
+}
+
+/*
+ * Save tdb_xattrs to a previously fetch_locked record
+ */
+
+static NTSTATUS xattr_tdb_save_attrs(struct db_record *rec,
+ const struct tdb_xattrs *attribs)
+{
+ TDB_DATA data = tdb_null;
+ NTSTATUS status;
+
+ status = xattr_tdb_push_attrs(talloc_tos(), attribs, &data);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("xattr_tdb_push_attrs failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = rec->store(rec, data, 0);
+
+ TALLOC_FREE(data.dptr);
+
+ return status;
+}
+
+/*
+ * Worker routine for getxattr and fgetxattr
+ */
+
+static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
+ const struct file_id *id,
+ const char *name, void *value, size_t size)
+{
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+ ssize_t result = -1;
+ NTSTATUS status;
+
+ DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
+ status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ errno = ENOATTR;
+ goto fail;
+ }
+
+ if (attribs->xattrs[i].value.length > size) {
+ errno = ERANGE;
+ goto fail;
+ }
+
+ memcpy(value, attribs->xattrs[i].value.data,
+ attribs->xattrs[i].value.length);
+ result = attribs->xattrs[i].value.length;
+
+ fail:
+ TALLOC_FREE(attribs);
+ return result;
+}
+
+static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ void *value, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_getattr(db, &id, name, value, size);
+}
+
+static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, void *value, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_getattr(db, &id, name, value, size);
+}
+
+/*
+ * Worker routine for setxattr and fsetxattr
+ */
+
+static int xattr_tdb_setattr(struct db_context *db_ctx,
+ const struct file_id *id, const char *name,
+ const void *value, size_t size, int flags)
+{
+ NTSTATUS status;
+ struct db_record *rec;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+
+ DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
+
+ if (rec == NULL) {
+ DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rec);
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ if (flags & XATTR_CREATE) {
+ TALLOC_FREE(rec);
+ errno = EEXIST;
+ return -1;
+ }
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ struct tdb_xattr *tmp;
+
+ if (flags & XATTR_REPLACE) {
+ TALLOC_FREE(rec);
+ errno = ENOATTR;
+ return -1;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(
+ attribs, attribs->xattrs, struct tdb_xattr,
+ attribs->num_xattrs + 1);
+
+ if (tmp == NULL) {
+ DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
+ TALLOC_FREE(rec);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ attribs->xattrs = tmp;
+ attribs->num_xattrs += 1;
+ }
+
+ attribs->xattrs[i].name = name;
+ attribs->xattrs[i].value.data = CONST_DISCARD(uint8 *, value);
+ attribs->xattrs[i].value.length = size;
+
+ status = xattr_tdb_save_attrs(rec, attribs);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name,
+ const void *value, size_t size, int flags)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_setattr(db, &id, name, value, size, flags);
+}
+
+static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_setattr(db, &id, name, value, size, flags);
+}
+
+/*
+ * Worker routine for listxattr and flistxattr
+ */
+
+static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
+ const struct file_id *id, char *list,
+ size_t size)
+{
+ NTSTATUS status;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+ size_t len = 0;
+
+ status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ errno = EINVAL;
+ return -1;
+ }
+
+ DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
+ attribs->num_xattrs));
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ size_t tmp;
+
+ DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
+ attribs->xattrs[i].name));
+
+ tmp = strlen(attribs->xattrs[i].name);
+
+ /*
+ * Try to protect against overflow
+ */
+
+ if (len + (tmp+1) < len) {
+ TALLOC_FREE(attribs);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Take care of the terminating NULL
+ */
+ len += (tmp + 1);
+ }
+
+ if (len > size) {
+ TALLOC_FREE(attribs);
+ errno = ERANGE;
+ return -1;
+ }
+
+ len = 0;
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ strlcpy(list+len, attribs->xattrs[i].name,
+ size-len);
+ len += (strlen(attribs->xattrs[i].name) + 1);
+ }
+
+ TALLOC_FREE(attribs);
+ return len;
+}
+
+static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
+ const char *path, char *list, size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_listattr(db, &id, list, size);
+}
+
+static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_listattr(db, &id, list, size);
+}
+
+/*
+ * Worker routine for removexattr and fremovexattr
+ */
+
+static int xattr_tdb_removeattr(struct db_context *db_ctx,
+ const struct file_id *id, const char *name)
+{
+ NTSTATUS status;
+ struct db_record *rec;
+ struct tdb_xattrs *attribs;
+ uint32_t i;
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
+
+ if (rec == NULL) {
+ DEBUG(0, ("xattr_tdb_lock_attrs failed\n"));
+ errno = EINVAL;
+ return -1;
+ }
+
+ status = xattr_tdb_pull_attrs(rec, &rec->value, &attribs);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("xattr_tdb_fetch_attrs failed: %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rec);
+ return -1;
+ }
+
+ for (i=0; i<attribs->num_xattrs; i++) {
+ if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ break;
+ }
+ }
+
+ if (i == attribs->num_xattrs) {
+ TALLOC_FREE(rec);
+ errno = ENOATTR;
+ return -1;
+ }
+
+ attribs->xattrs[i] =
+ attribs->xattrs[attribs->num_xattrs-1];
+ attribs->num_xattrs -= 1;
+
+ if (attribs->num_xattrs == 0) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ return 0;
+ }
+
+ status = xattr_tdb_save_attrs(rec, attribs);
+
+ TALLOC_FREE(rec);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("save failed: %s\n", nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
+ const char *path, const char *name)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_removeattr(db, &id, name);
+}
+
+static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ return xattr_tdb_removeattr(db, &id, name);
+}
+
+/*
+ * Open the tdb file upon VFS_CONNECT
+ */
+
+static bool xattr_tdb_init(int snum, struct db_context **p_db)
+{
+ struct db_context *db;
+ const char *dbname;
+
+ dbname = lp_parm_const_string(snum, "xattr", "tdb",
+ lock_path("xattr.tdb"));
+
+ if (dbname == NULL) {
+ errno = ENOSYS;
+ return false;
+ }
+
+ become_root();
+ db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+ unbecome_root();
+
+ if (db == NULL) {
+ errno = ENOTSUP;
+ return false;
+ }
+
+ *p_db = db;
+ return true;
+}
+
+/*
+ * On unlink we need to delete the tdb record
+ */
+static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+ struct db_record *rec;
+ int ret;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, path);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
+
+ /*
+ * If rec == NULL there's not much we can do about it
+ */
+
+ if (rec != NULL) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ }
+
+ return 0;
+}
+
+/*
+ * On rmdir we need to delete the tdb record
+ */
+static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
+{
+ SMB_STRUCT_STAT sbuf;
+ struct file_id id;
+ struct db_context *db;
+ struct db_record *rec;
+ int ret;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
+
+ if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_RMDIR(handle, path);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+
+ rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
+
+ /*
+ * If rec == NULL there's not much we can do about it
+ */
+
+ if (rec != NULL) {
+ rec->delete_rec(rec);
+ TALLOC_FREE(rec);
+ }
+
+ return 0;
+}
+
+/*
+ * Destructor for the VFS private data
+ */
+
+static void close_xattr_db(void **data)
+{
+ struct db_context **p_db = (struct db_context **)data;
+ TALLOC_FREE(*p_db);
+}
+
+static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
+ const char *user)
+{
+ fstring sname;
+ int res, snum;
+ struct db_context *db;
+
+ res = SMB_VFS_NEXT_CONNECT(handle, service, user);
+ if (res < 0) {
+ return res;
+ }
+
+ fstrcpy(sname, service);
+ snum = find_service(sname);
+ if (snum == -1) {
+ /*
+ * Should not happen, but we should not fail just *here*.
+ */
+ return 0;
+ }
+
+ if (!xattr_tdb_init(snum, &db)) {
+ DEBUG(5, ("Could not init xattr tdb\n"));
+ lp_do_parameter(snum, "ea support", "False");
+ return 0;
+ }
+
+ lp_do_parameter(snum, "ea support", "True");
+
+ SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
+ struct db_context, return -1);
+
+ return 0;
+}
+
+/* VFS operations structure */
+
+static const vfs_op_tuple xattr_tdb_ops[] = {
+ {SMB_VFS_OP(xattr_tdb_getxattr), SMB_VFS_OP_GETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fgetxattr), SMB_VFS_OP_FGETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_setxattr), SMB_VFS_OP_SETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fsetxattr), SMB_VFS_OP_FSETXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_listxattr), SMB_VFS_OP_LISTXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_flistxattr), SMB_VFS_OP_FLISTXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_removexattr), SMB_VFS_OP_REMOVEXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_fremovexattr), SMB_VFS_OP_FREMOVEXATTR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_rmdir), SMB_VFS_OP_RMDIR,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(xattr_tdb_connect), SMB_VFS_OP_CONNECT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_xattr_tdb_init(void);
+NTSTATUS vfs_xattr_tdb_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
+ xattr_tdb_ops);
+}
diff --git a/source3/modules/vfs_zfsacl.c b/source3/modules/vfs_zfsacl.c
index 0fe21b2909..ce2e28771f 100644
--- a/source3/modules/vfs_zfsacl.c
+++ b/source3/modules/vfs_zfsacl.c
@@ -34,8 +34,9 @@
* read the local file's acls and return it in NT form
* using the NFSv4 format conversion
*/
-static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info,
- struct security_descriptor **ppdesc)
+static NTSTATUS zfs_get_nt_acl_common(const char *name,
+ uint32 security_info,
+ SMB4ACL_T **ppacl)
{
int naces, i;
ace_t *acebuf;
@@ -43,11 +44,13 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info,
TALLOC_CTX *mem_ctx;
/* read the number of file aces */
- if((naces = acl(fsp->fsp_name, ACE_GETACLCNT, 0, NULL)) == -1) {
+ if((naces = acl(name, ACE_GETACLCNT, 0, NULL)) == -1) {
if(errno == ENOSYS) {
- DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not supported on the filesystem where the file reside"));
+ DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
+ "supported on the filesystem where the file "
+ "reside", name));
} else {
- DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", fsp->fsp_name,
+ DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", name,
strerror(errno)));
}
return map_nt_error_from_unix(errno);
@@ -59,8 +62,8 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info,
return NT_STATUS_NO_MEMORY;
}
/* read the aces into the field */
- if(acl(fsp->fsp_name, ACE_GETACL, naces, acebuf) < 0) {
- DEBUG(9, ("acl(ACE_GETACL, %s): %s ", fsp->fsp_name,
+ if(acl(name, ACE_GETACL, naces, acebuf) < 0) {
+ DEBUG(9, ("acl(ACE_GETACL, %s): %s ", name,
strerror(errno)));
return map_nt_error_from_unix(errno);
}
@@ -92,7 +95,8 @@ static NTSTATUS zfs_get_nt_acl(struct files_struct *fsp, uint32 security_info,
return NT_STATUS_NO_MEMORY;
}
- return smb_get_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
+ *ppacl = pacl;
+ return NT_STATUS_OK;
}
/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
@@ -143,7 +147,9 @@ static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
/* store acl */
if(acl(fsp->fsp_name, ACE_SETACL, naces, acebuf)) {
if(errno == ENOSYS) {
- DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not supported on the filesystem where the file reside"));
+ DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
+ "supported on the filesystem where the file "
+ "reside", fsp->fsp_name));
} else {
DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp->fsp_name,
strerror(errno)));
@@ -168,23 +174,39 @@ static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
struct files_struct *fsp,
- int fd, uint32 security_info,
+ uint32 security_info,
struct security_descriptor **ppdesc)
{
- return zfs_get_nt_acl(fsp, security_info, ppdesc);
+ SMB4ACL_T *pacl;
+ NTSTATUS status;
+
+ status = zfs_get_nt_acl_common(fsp->fsp_name, security_info, &pacl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return smb_fget_nt_acl_nfs4(fsp, security_info, ppdesc, pacl);
}
static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
const char *name, uint32 security_info,
struct security_descriptor **ppdesc)
{
- return zfs_get_nt_acl(fsp, security_info, ppdesc);
+ SMB4ACL_T *pacl;
+ NTSTATUS status;
+
+ status = zfs_get_nt_acl_common(name, security_info, &pacl);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc,
+ pacl);
}
static NTSTATUS zfsacl_fset_nt_acl(vfs_handle_struct *handle,
files_struct *fsp,
- int fd, uint32 security_info_sent,
+ uint32 security_info_sent,
SEC_DESC *psd)
{
return zfs_set_nt_acl(handle, fsp, security_info_sent, psd);
@@ -200,7 +222,7 @@ static NTSTATUS zfsacl_set_nt_acl(vfs_handle_struct *handle,
/* VFS operations structure */
-static vfs_op_tuple zfsacl_ops[] = {
+static vfs_op_tuple zfsacl_ops[] = {
{SMB_VFS_OP(zfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(zfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,