[SCM] Samba Shared Repository - branch master updated - 9872dbf439e94ffd56019f789145c4b5eb3e606c

Tim Prouty tprouty at samba.org
Mon Jan 12 06:17:40 GMT 2009


The branch, master has been updated
       via  9872dbf439e94ffd56019f789145c4b5eb3e606c (commit)
       via  a1e428914b9bc468d99775607781ff15169defa4 (commit)
       via  5c48ba6563ff025037b9337d34b9aa13de610fba (commit)
      from  ce5eded7e03d86d5d7f2ee1a9d975fae116d2306 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 9872dbf439e94ffd56019f789145c4b5eb3e606c
Author: Tim Prouty <tprouty at samba.org>
Date:   Fri Jan 2 17:35:04 2009 -0800

    s3: Differentiate between posix files with colons and actual streams
    
    It is possible for a posix file created locally or over nfs to have a
    ":" in the name.  Since ":" is a reserved character in windows,
    filenames containing a colon must be mangled in a directory listing.
    Right now files containing colons will not even be displayed in
    directory listings if streams modules are in use.  During the
    directory listing the file will be detected as a stream because of the
    colon, but the streams module will fail to find the stream since it
    doesn't exist.  This fix adds a step to is_ntfs_stream_name that stats
    the filename to differentiate between actual streams and files
    containing colons.
    
    While this is an improvement, it isn't perfect. Consider the case
    where there is a file on disk called "a.txt:s1" and also a file called
    "a.txt" that has a stream called "s1".  This patch will always
    preference "a.txt:s1" over a.txt's s1 stream.
    
    The real issue is that at the vfs level, the vfs modules have no way
    to tell between a demangled name with a colon and an actual stream.  A
    more invasive, but better, long-term fix would be to add all paths
    that come over the wire into a struct containing metadata about the
    path.  This metadata could include a flag to indicate whether the path
    came over the wire with a colon ":" (guaranteeing that the client is
    requesting a stream). Passing this struct down to the lower levels,
    including all path-based vfs calls, would allow the above case to be
    handled correctly in all cases.

commit a1e428914b9bc468d99775607781ff15169defa4
Author: Tim Prouty <tprouty at samba.org>
Date:   Fri Dec 12 14:32:48 2008 -0800

    s3: Add OneFS alternate data streams implementation

commit 5c48ba6563ff025037b9337d34b9aa13de610fba
Author: Tim Prouty <tprouty at samba.org>
Date:   Tue Dec 30 17:17:24 2008 -0800

    s3: General cleanup of the open path in the OneFS vfs module

-----------------------------------------------------------------------

Summary of changes:
 source3/Makefile.in             |    2 +-
 source3/modules/onefs.h         |   35 ++-
 source3/modules/onefs_acl.c     |    6 +-
 source3/modules/onefs_open.c    |   70 +++--
 source3/modules/onefs_streams.c |  580 +++++++++++++++++++++++++++++++++++++++
 source3/modules/onefs_system.c  |   11 +-
 source3/modules/vfs_onefs.c     |   29 ++-
 source3/smbd/nttrans.c          |   36 +++-
 8 files changed, 725 insertions(+), 44 deletions(-)
 create mode 100644 source3/modules/onefs_streams.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 624156b..a4b9bda 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -651,7 +651,7 @@ VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
 VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o
 VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o
 VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \
-		modules/onefs_open.o
+		modules/onefs_open.o modules/onefs_streams.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
index 8d0f45a..6e5eae3 100644
--- a/source3/modules/onefs.h
+++ b/source3/modules/onefs.h
@@ -67,6 +67,32 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
 			   int *pinfo,
 			   SMB_STRUCT_STAT *psbuf);
 
+int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp);
+
+int onefs_rename(vfs_handle_struct *handle, const char *oldname,
+		 const char *newname);
+
+int onefs_stat(vfs_handle_struct *handle, const char *fname,
+	       SMB_STRUCT_STAT *sbuf);
+
+int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp,
+		SMB_STRUCT_STAT *sbuf);
+
+int onefs_lstat(vfs_handle_struct *handle, const char *path,
+		SMB_STRUCT_STAT *sbuf);
+
+int onefs_unlink(vfs_handle_struct *handle, const char *path);
+
+int onefs_chflags(vfs_handle_struct *handle, const char *path,
+		  unsigned int flags);
+
+NTSTATUS onefs_streaminfo(vfs_handle_struct *handle,
+			  struct files_struct *fsp,
+			  const char *fname,
+			  TALLOC_CTX *mem_ctx,
+			  unsigned int *num_streams,
+			  struct stream_struct **streams);
+
 NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 			   uint32 security_info, SEC_DESC **ppdesc);
 
@@ -75,13 +101,14 @@ NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
 
 NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 			   uint32 security_info_sent, SEC_DESC *psd);
-
-
 /*
  * Utility functions
  */
-NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd,
-			struct ifs_security_descriptor *sd);
+NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd,
+			      struct ifs_security_descriptor *sd);
+
+NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+				      char **pbase, char **pstream);
 
 /*
  * System Interfaces
diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c
index 5351118..9258e0c 100644
--- a/source3/modules/onefs_acl.c
+++ b/source3/modules/onefs_acl.c
@@ -696,8 +696,8 @@ onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
  *
  * @return NTSTATUS_OK if successful
  */
-NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd,
-			struct ifs_security_descriptor *sd)
+NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd,
+			      struct ifs_security_descriptor *sd)
 {
 	struct ifs_security_acl dacl, sacl, *daclp, *saclp;
 	struct ifs_identity owner, group, *ownerp, *groupp;
@@ -789,7 +789,7 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 
 	DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name ));
 
-	status = onefs_setup_sd(security_info_sent, psd, &sd);
+	status = onefs_samba_sd_to_sd(security_info_sent, psd, &sd);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3, ("SD initialization failure: %s", nt_errstr(status)));
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
index a86d399..c8415de 100644
--- a/source3/modules/onefs_open.c
+++ b/source3/modules/onefs_open.c
@@ -88,6 +88,9 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
 	int local_flags = flags;
 	bool file_existed = VALID_STAT(*psbuf);
 	const char *wild;
+	char *base = NULL;
+	char *stream = NULL;
+	int base_fd = -1;
 
 	fsp->fh->fd = -1;
 	errno = EPERM;
@@ -191,9 +194,25 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
 	if (!lp_oplocks(SNUM(conn)))
 		oplock_request = 0;
 
+	/* Stream handling */
+	if (is_ntfs_stream_name(path)) {
+		status = onefs_split_ntfs_stream_name(talloc_tos(), path,
+						      &base, &stream);
+	}
+	/* It's a stream, so pass in the base_fd */
+	if (stream != NULL) {
+		SMB_ASSERT(fsp->base_fsp);
+
+		DEBUG(10,("Opening a stream: base=%s(%d), stream=%s",
+			  base, fsp->base_fsp->fh->fd, stream));
+
+		base_fd = fsp->base_fsp->fh->fd;
+	}
+
 	fsp->fh->fd = onefs_sys_create_file(conn,
-					    -1,
-					    path,
+					    base_fd,
+					    stream != NULL ? stream :
+					    (base != NULL ? base : path),
 					    access_mask,
 					    open_access_mask,
 					    share_access,
@@ -427,6 +446,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 	bool def_acl = False;
 	bool posix_open = False;
 	bool new_file_created = False;
+	bool clear_ads = False;
 	struct file_id id;
 	mode_t new_unx_mode = (mode_t)0;
 	mode_t unx_mode = (mode_t)0;
@@ -575,8 +595,6 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 		 * (requiring delete access) then recreates it.
 		 */
 		case FILE_SUPERSEDE:
-			/* If file exists replace/overwrite. If file doesn't
-			 * exist create. */
 			/**
 			 * @todo: Clear all file attributes?
 			 * http://www.osronline.com/article.cfm?article=302
@@ -586,12 +604,14 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 			 * exist create.
 			 */
 			flags2 |= (O_CREAT | O_TRUNC);
+			clear_ads = true;
 			break;
 
 		case FILE_OVERWRITE_IF:
 			/* If file exists replace/overwrite. If file doesn't
 			 * exist create. */
 			flags2 |= (O_CREAT | O_TRUNC);
+			clear_ads = true;
 			break;
 
 		case FILE_OPEN:
@@ -617,6 +637,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 				return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 			}
 			flags2 |= O_TRUNC;
+			clear_ads = true;
 			break;
 
 		case FILE_CREATE:
@@ -748,19 +769,8 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 		 */
 		flags2 &= ~(O_CREAT|O_TRUNC);
 
-		/**
-		 * XXX: TODO
-		 * Apparently this is necessary because we ship with
-		 * lp_acl_check_permissions = no.  It is set to no because our
-		 * ifs_createfile does the access check correctly.  This check
-		 * was added in the last merge, and the question is why is it
-		 * necessary?  Check out Bug 25547 and Bug 14596.  The key is
-		 * to figure out what case this is covering, and do some
-		 * testing to see if it's actually necessary.  If it is, maybe
-		 * it should go upstream in open.c.
-		 */
-		if (!lp_acl_check_permissions(SNUM(conn)) &&
-		    (access_mask & DELETE_ACCESS)) {
+		/* Deny DELETE_ACCESS explicitly if the share is read only. */
+		if (access_mask & DELETE_ACCESS) {
 			return map_nt_error_from_unix(EACCES);
 		}
 	}
@@ -1111,6 +1121,16 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
 
 	SMB_ASSERT(lck != NULL);
 
+	/* Delete streams if create_disposition requires it */
+	if (file_existed && clear_ads) {
+		status = delete_all_streams(conn, fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(lck);
+			fd_close(fsp);
+			return status;
+		}
+	}
+
 	/* note that we ignore failure for the following. It is
            basically a hack for NFS, and NFS will never set one of
            these only read them. Nobody but Samba can ever set a deny
@@ -1599,6 +1619,8 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn,
 		goto fail;
 	}
 
+	/* Open the base file */
+
 	for (i=0; i<num_streams; i++) {
 		char *streamname;
 
@@ -1738,8 +1760,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
 	}
 
 	if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
-	    && is_ntfs_stream_name(fname)
-	    && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
+	    && is_ntfs_stream_name(fname)) {
 		char *base;
 		uint32 base_create_disposition;
 
@@ -1748,8 +1769,8 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
 			goto fail;
 		}
 
-		status = split_ntfs_stream_name(talloc_tos(), fname,
-						&base, NULL);
+		status = onefs_split_ntfs_stream_name(talloc_tos(), fname,
+						      &base, NULL);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(10, ("onefs_create_file_unixpath: "
 				  "split_ntfs_stream_name failed: %s\n",
@@ -1778,7 +1799,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
 			    FILE_SHARE_DELETE),		/* share_access */
 			base_create_disposition,	/* create_disposition*/
 			0,				/* create_options */
-			0,				/* file_attributes */
+			file_attributes,		/* file_attributes */
 			NO_OPLOCK,			/* oplock_request */
 			0,				/* allocation_size */
 			NULL,				/* sd */
@@ -1792,11 +1813,6 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
 				  "failed: %s\n", base, nt_errstr(status)));
 			goto fail;
 		}
-		/*
-		 * we don't need to low level fd: This might conflict with
-		 * OneFS streams.
-		 */
-		fd_close(base_fsp);
 	}
 
 	/* Covert generic bits in the security descriptor. */
diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c
new file mode 100644
index 0000000..55ce11e
--- /dev/null
+++ b/source3/modules/onefs_streams.c
@@ -0,0 +1,580 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Support for OneFS Alternate Data Streams
+ *
+ * Copyright (C) Tim Prouty, 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
+ * 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 "onefs.h"
+#include <sys/isi_enc.h>
+
+/*
+ * OneFS stores streams without the explicit :$DATA at the end, so this strips
+ * it off.  All onefs_stream functions must call through this instead of
+ * split_ntfs_stream_name directly.
+ */
+NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+				      char **pbase, char **pstream)
+{
+	NTSTATUS status;
+	char *stream;
+
+	status = split_ntfs_stream_name(mem_ctx, fname, pbase, pstream);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	/* Default $DATA stream.  */
+	if (pstream == NULL || *pstream == NULL) {
+		return NT_STATUS_OK;
+	}
+
+	/* Strip off the $DATA. */
+	stream = strrchr_m(*pstream, ':');
+	SMB_ASSERT(stream);
+	stream[0] = '\0';
+
+	return NT_STATUS_OK;
+}
+
+int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp)
+{
+	int ret2, ret = 0;
+
+	if (fsp->base_fsp) {
+		ret = SMB_VFS_NEXT_CLOSE(handle, fsp->base_fsp);
+	}
+	ret2 = SMB_VFS_NEXT_CLOSE(handle, fsp);
+
+	return ret ? ret : ret2;
+}
+
+/*
+ * Get the ADS directory fd for a file.
+ */
+static int get_stream_dir_fd(connection_struct *conn, const char *base,
+			     int *base_fdp)
+{
+	int base_fd;
+	int dir_fd;
+	int saved_errno;
+
+	/* If a valid base_fdp was given, use it. */
+	if (base_fdp && *base_fdp >= 0) {
+		base_fd = *base_fdp;
+	} else {
+		base_fd = onefs_sys_create_file(conn,
+						-1,
+						base,
+						0,
+						0,
+						0,
+						0,
+						0,
+						0,
+						INTERNAL_OPEN_ONLY,
+						0,
+						NULL,
+						0,
+						NULL);
+		if (base_fd < 0) {
+			return -1;
+		}
+	}
+
+	/* Open the ADS directory. */
+	dir_fd = onefs_sys_create_file(conn,
+					base_fd,
+					".",
+					0,
+					FILE_READ_DATA,
+					0,
+					0,
+					0,
+					0,
+					INTERNAL_OPEN_ONLY,
+					0,
+					NULL,
+					0,
+					NULL);
+
+	/* Close base_fd if it's not need or on error. */
+	if (!base_fdp || dir_fd < 0) {
+		saved_errno = errno;
+		close(base_fd);
+		errno = saved_errno;
+	}
+
+	/* Set the out base_fdp if successful and it was requested. */
+	if (base_fdp && dir_fd >= 0) {
+		*base_fdp = base_fd;
+	}
+
+	return dir_fd;
+}
+
+int onefs_rename(vfs_handle_struct *handle, const char *oldname,
+		 const char *newname)
+{
+	TALLOC_CTX *frame = NULL;
+	int ret = -1;
+	int dir_fd, saved_errno;
+	bool old_is_stream;
+	bool new_is_stream;
+	char *obase = NULL;
+	char *osname = NULL;
+	char *nbase = NULL;
+	char *nsname = NULL;
+
+	old_is_stream = is_ntfs_stream_name(oldname);
+	new_is_stream = is_ntfs_stream_name(newname);
+
+	if (!old_is_stream && !new_is_stream) {
+		return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
+	}
+
+	frame = talloc_stackframe();
+
+	if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(),
+							  oldname, &obase,
+							  &osname))) {
+		errno = ENOMEM;
+		goto done;
+	}
+
+	if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(),
+							  newname, &nbase,
+							  &nsname))) {
+		errno = ENOMEM;
+		goto done;
+	}
+
+	dir_fd = get_stream_dir_fd(handle->conn, obase, NULL);
+	if (dir_fd < -1) {
+		goto done;
+	}
+
+	DEBUG(8,("onefs_rename called for %s : %s  => %s : %s\n",
+		obase, osname,  nbase, nsname));
+
+	/* Handle rename of stream to default stream specially. */
+	if (nsname == NULL) {
+		ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, AT_FDCWD,
+				   nbase, ENC_DEFAULT);
+	} else {
+		ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, dir_fd, nsname,
+				   ENC_DEFAULT);
+	}
+
+ done:
+	saved_errno = errno;
+	close(dir_fd);
+	errno = saved_errno;
+	TALLOC_FREE(frame);
+	return ret;
+}
+
+/*
+ * Merge a base file's sbuf into the a streams's sbuf.
+ */
+static void merge_stat(SMB_STRUCT_STAT *stream_sbuf,
+		       const SMB_STRUCT_STAT *base_sbuf)
+{
+	int dos_flags = (UF_DOS_NOINDEX | UF_DOS_ARCHIVE |
+	    UF_DOS_HIDDEN | UF_DOS_RO | UF_DOS_SYSTEM);
+	stream_sbuf->st_mtime = base_sbuf->st_mtime;
+	stream_sbuf->st_ctime = base_sbuf->st_ctime;
+	stream_sbuf->st_atime = base_sbuf->st_atime;
+	stream_sbuf->st_flags &= ~dos_flags;
+	stream_sbuf->st_flags |= base_sbuf->st_flags & dos_flags;
+}
+
+static int stat_stream(vfs_handle_struct *handle, const char *base,
+		       const char *stream, SMB_STRUCT_STAT *sbuf, int flags)
+{
+	SMB_STRUCT_STAT base_sbuf;
+	int base_fd = -1, dir_fd, ret, saved_errno;
+
+	dir_fd = get_stream_dir_fd(handle->conn, base, &base_fd);
+	if (dir_fd < 0) {
+		return -1;
+	}
+
+	/* Stat the stream. */
+	ret = enc_fstatat(dir_fd, stream, ENC_DEFAULT, sbuf, flags);
+	if (ret != -1) {
+		/* Now stat the base file and merge the results. */
+		ret = sys_fstat(base_fd, &base_sbuf);
+		if (ret != -1) {
+			merge_stat(sbuf, &base_sbuf);
+		}
+	}
+
+	saved_errno = errno;
+	close(dir_fd);
+	close(base_fd);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list