svn commit: samba r23101 - in branches/SAMBA_3_0_RELEASE/source: include locking smbd

jerry at samba.org jerry at samba.org
Wed May 23 22:46:32 GMT 2007


Author: jerry
Date: 2007-05-23 22:46:30 +0000 (Wed, 23 May 2007)
New Revision: 23101

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=23101

Log:
grab remainder of rename fixes
Modified:
   branches/SAMBA_3_0_RELEASE/source/include/smb.h
   branches/SAMBA_3_0_RELEASE/source/locking/locking.c
   branches/SAMBA_3_0_RELEASE/source/smbd/open.c
   branches/SAMBA_3_0_RELEASE/source/smbd/reply.c
   branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c


Changeset:
Modified: branches/SAMBA_3_0_RELEASE/source/include/smb.h
===================================================================
--- branches/SAMBA_3_0_RELEASE/source/include/smb.h	2007-05-23 21:32:10 UTC (rev 23100)
+++ branches/SAMBA_3_0_RELEASE/source/include/smb.h	2007-05-23 22:46:30 UTC (rev 23101)
@@ -748,6 +748,7 @@
 };
 
 #define SHARE_MODE_FLAG_POSIX_OPEN	0x1
+#define SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE      0x2
 
 /* struct returned by get_share_modes */
 struct share_mode_entry {
@@ -765,7 +766,7 @@
 	SMB_INO_T inode;
 	unsigned long share_file_id;
 	uint32 uid;		/* uid of file opener. */
-	uint16 flags;		/* POSIX_OPEN only defined so far... */
+	uint16 flags;		/* See SHARE_MODE_XX above. */
 };
 
 /* oplock break message definition - linearization of share_mode_entry.

Modified: branches/SAMBA_3_0_RELEASE/source/locking/locking.c
===================================================================
--- branches/SAMBA_3_0_RELEASE/source/locking/locking.c	2007-05-23 21:32:10 UTC (rev 23100)
+++ branches/SAMBA_3_0_RELEASE/source/locking/locking.c	2007-05-23 22:46:30 UTC (rev 23101)
@@ -993,10 +993,13 @@
 }
 
 void set_share_mode(struct share_mode_lock *lck, files_struct *fsp,
-			uid_t uid, uint16 mid, uint16 op_type)
+			uid_t uid, uint16 mid, uint16 op_type, BOOL initial_delete_on_close_allowed)
 {
 	struct share_mode_entry entry;
 	fill_share_mode_entry(&entry, fsp, uid, mid, op_type);
+	if (initial_delete_on_close_allowed) {
+		entry.flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+	}
 	add_share_mode_entry(lck, &entry);
 }
 
@@ -1196,6 +1199,22 @@
 	return NT_STATUS_OK;
 }
 
+/****************************************************************************
+ Do we have an open file handle that created this entry ?
+****************************************************************************/
+
+BOOL can_set_initial_delete_on_close(const struct share_mode_lock *lck)
+{
+	int i;
+
+	for (i=0; i<lck->num_share_modes; i++) {
+		if (lck->share_modes[i].flags & SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE) {
+			return True;
+		}
+	}
+	return False;
+}
+
 /*************************************************************************
  Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail.
  (Should this be in locking.c.... ?).
@@ -1296,6 +1315,31 @@
 	return True;
 }
 
+/****************************************************************************
+ Sets the allow initial delete on close flag for this share mode.
+****************************************************************************/
+
+BOOL set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, BOOL delete_on_close)
+{
+	struct share_mode_entry entry, *e;
+
+	/* Don't care about the pid owner being correct here - just a search. */
+	fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK);
+
+	e = find_share_mode_entry(lck, &entry);
+	if (e == NULL) {
+		return False;
+	}
+
+	if (delete_on_close) {
+		e->flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+	} else {
+		e->flags &= ~SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE;
+	}
+	lck->modified = True;
+	return True;
+}
+
 struct forall_state {
 	void (*fn)(const struct share_mode_entry *entry,
 		   const char *sharepath,

Modified: branches/SAMBA_3_0_RELEASE/source/smbd/open.c
===================================================================
--- branches/SAMBA_3_0_RELEASE/source/smbd/open.c	2007-05-23 21:32:10 UTC (rev 23100)
+++ branches/SAMBA_3_0_RELEASE/source/smbd/open.c	2007-05-23 22:46:30 UTC (rev 23101)
@@ -47,7 +47,12 @@
 	NTSTATUS status = NT_STATUS_OK;
 
 #ifdef O_NOFOLLOW
-	if (!lp_symlinks(SNUM(conn))) {
+	/* 
+	 * Never follow symlinks on a POSIX client. The
+	 * client should be doing this.
+	 */
+
+	if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
 		flags |= O_NOFOLLOW;
 	}
 #endif
@@ -1120,6 +1125,7 @@
 	BOOL file_existed = VALID_STAT(*psbuf);
 	BOOL def_acl = False;
 	BOOL posix_open = False;
+	BOOL new_file_created = False;
 	SMB_DEV_T dev = 0;
 	SMB_INO_T inode = 0;
 	NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
@@ -1760,28 +1766,31 @@
 			fsp->oplock_type = NO_OPLOCK;
 		}
 	}
-	set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type);
 
-	if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED ||
-	    info == FILE_WAS_SUPERSEDED) {
+	if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) {
+		new_file_created = True;
+	}
 
-		/* Handle strange delete on close create semantics. */
-		if (create_options & FILE_DELETE_ON_CLOSE) {
-			status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+	set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created);
 
-			if (!NT_STATUS_IS_OK(status)) {
-				/* Remember to delete the mode we just added. */
-				del_share_mode(lck, fsp);
-				TALLOC_FREE(lck);
-				fd_close(conn,fsp);
-				file_free(fsp);
-				return status;
-			}
-			/* Note that here we set the *inital* delete on close flag,
-			   not the regular one. The magic gets handled in close. */
-			fsp->initial_delete_on_close = True;
+	/* Handle strange delete on close create semantics. */
+	if ((create_options & FILE_DELETE_ON_CLOSE) && can_set_initial_delete_on_close(lck)) {
+		status = can_set_delete_on_close(fsp, True, new_dos_attributes);
+
+		if (!NT_STATUS_IS_OK(status)) {
+			/* Remember to delete the mode we just added. */
+			del_share_mode(lck, fsp);
+			TALLOC_FREE(lck);
+			fd_close(conn,fsp);
+			file_free(fsp);
+			return status;
 		}
+		/* Note that here we set the *inital* delete on close flag,
+		   not the regular one. The magic gets handled in close. */
+		fsp->initial_delete_on_close = True;
+	}
 	
+	if (new_file_created) {
 		/* Files should be initially set as archive */
 		if (lp_map_archive(SNUM(conn)) ||
 		    lp_store_dos_attributes(SNUM(conn))) {
@@ -2139,7 +2148,7 @@
 		return status;
 	}
 
-	set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK);
+	set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True);
 
 	/* For directories the delete on close bit at open time seems
 	   always to be honored on close... See test 19 in Samba4 BASE-DELETE. */

Modified: branches/SAMBA_3_0_RELEASE/source/smbd/reply.c
===================================================================
--- branches/SAMBA_3_0_RELEASE/source/smbd/reply.c	2007-05-23 21:32:10 UTC (rev 23100)
+++ branches/SAMBA_3_0_RELEASE/source/smbd/reply.c	2007-05-23 22:46:30 UTC (rev 23101)
@@ -1790,7 +1790,7 @@
  Check if a user is allowed to rename a file.
 ********************************************************************/
 
-static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst)
+static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
 {
 	files_struct *fsp;
 	uint32 fmode;
@@ -1811,7 +1811,10 @@
 
 	status = open_file_ntcreate(conn, fname, pst,
 				DELETE_ACCESS,
-				FILE_SHARE_READ|FILE_SHARE_WRITE,
+				/* If we're checking our fsp don't deny for delete. */
+				self_open ?
+					FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
+					FILE_SHARE_READ|FILE_SHARE_WRITE,
 				FILE_OPEN,
 				0,
 				FILE_ATTRIBUTE_NORMAL,
@@ -4192,7 +4195,9 @@
 	ZERO_STRUCT(sbuf);
 
 	status = unix_convert(conn, newname, False, newname_last_component, &sbuf);
-	if (!NT_STATUS_IS_OK(status)) {
+	/* We expect this to be NT_STATUS_OBJECT_PATH_NOT_FOUND */
+	if (!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) {
+		return NT_STATUS_OBJECT_NAME_COLLISION;
 		return status;
 	}
 
@@ -4260,9 +4265,20 @@
 		return NT_STATUS_OBJECT_NAME_COLLISION;
 	}
 
-	status = can_rename(conn,fsp->fsp_name,attrs,&sbuf);
+	/* Ensure we have a valid stat struct for the source. */
+	if (fsp->fh->fd != -1) {
+		if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
+			return map_nt_error_from_unix(errno);
+		}
+	} else {
+		if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
+			return map_nt_error_from_unix(errno);
+		}
+	}
 
-	if (dest_exists && !NT_STATUS_IS_OK(status)) {
+	status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+
+	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
 			nt_errstr(status), fsp->fsp_name,newname));
 		if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
@@ -4277,9 +4293,33 @@
 	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
 
 	if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+		uint32 create_options = fsp->fh->private_options;
+
 		DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
 			fsp->fsp_name,newname));
+
 		rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
+
+		/*
+		 * A rename acts as a new file create w.r.t. allowing an initial delete
+		 * on close, probably because in Windows there is a new handle to the
+		 * new file. If initial delete on close was requested but not
+		 * originally set, we need to set it here. This is probably not 100% correct,
+		 * but will work for the CIFSFS client which in non-posix mode
+		 * depends on these semantics. JRA.
+		 */
+
+		set_allow_initial_delete_on_close(lck, fsp, True);
+
+		if (create_options & FILE_DELETE_ON_CLOSE) {
+			status = can_set_delete_on_close(fsp, True, 0);
+
+			if (NT_STATUS_IS_OK(status)) {
+				/* Note that here we set the *inital* delete on close flag,
+				 * not the regular one. The magic gets handled in close. */
+				fsp->initial_delete_on_close = True;
+			}
+		}
 		TALLOC_FREE(lck);
 		return NT_STATUS_OK;	
 	}
@@ -4530,7 +4570,7 @@
 			return status;
 		}
 
-		status = can_rename(conn,directory,attrs,&sbuf1);
+		status = can_rename(conn,directory,attrs,&sbuf1,False);
 
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(3,("rename_internals: Error %s rename %s -> "
@@ -4658,7 +4698,7 @@
 				  fname, nt_errstr(status)));
 			continue;
 		}
-		status = can_rename(conn,fname,attrs,&sbuf1);
+		status = can_rename(conn,fname,attrs,&sbuf1,False);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(6, ("rename %s refused\n", fname));
 			continue;

Modified: branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c
===================================================================
--- branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c	2007-05-23 21:32:10 UTC (rev 23100)
+++ branches/SAMBA_3_0_RELEASE/source/smbd/trans2.c	2007-05-23 22:46:30 UTC (rev 23101)
@@ -4507,10 +4507,11 @@
 	pstrcpy(base_name, fname);
 	p = strrchr_m(base_name, '/');
 	if (p) {
-		*p = '\0';
+		p[1] = '\0';
+	} else {
+		pstrcpy(base_name, "./");
 	}
 	/* Append the new name. */
-	pstrcat(base_name, "/");
 	pstrcat(base_name, newname);
 
 	if (fsp) {
@@ -5632,9 +5633,17 @@
 			 * to do this call. JRA.
 			 */
 			pstrcpy(fname, fsp->fsp_name);
-			if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
-				DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
-				return UNIXERROR(ERRDOS,ERRbadpath);
+			if (INFO_LEVEL_IS_UNIX(info_level)) {
+				/* Always do lstat for UNIX calls. */
+				if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+					DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
+					return UNIXERROR(ERRDOS,ERRbadpath);
+				}
+			} else {
+				if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
+					DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+					return UNIXERROR(ERRDOS,ERRbadpath);
+				}
 			}
 		} else if (fsp && fsp->print_file) {
 			/*
@@ -5693,14 +5702,18 @@
 			return ERROR_NT(status);
 		}
 
-		/*
-		 * For CIFS UNIX extensions the target name may not exist.
-		 */
+		if (INFO_LEVEL_IS_UNIX(info_level)) {
+			/*
+			 * For CIFS UNIX extensions the target name may not exist.
+			 */
 
-		if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) {
-			DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno)));
+			/* Always do lstat for UNIX calls. */
+			SMB_VFS_LSTAT(conn,fname,&sbuf);
+
+		} else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+			DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
 			return UNIXERROR(ERRDOS,ERRbadpath);
-		}    
+		}
 	}
 
 	if (!CAN_WRITE(conn)) {



More information about the samba-cvs mailing list