support-rename-case-insensitive-filenames   [plain text]


Index: samba/source/smbd/reply.c
===================================================================
--- samba/source/smbd/reply.c.orig
+++ samba/source/smbd/reply.c
@@ -4240,6 +4240,7 @@ NTSTATUS rename_internals_fsp(connection
 	NTSTATUS status = NT_STATUS_OK;
 	BOOL dest_exists;
 	struct share_mode_lock *lck = NULL;
+	BOOL check_dest_exist = True;
 
 	ZERO_STRUCT(sbuf);
 
@@ -4293,6 +4294,13 @@ NTSTATUS rename_internals_fsp(connection
 			 * the original.
 			 */
 			pstrcpy(p+1, newname_last_component);
+			/*
+			 * We are renaming the same item to a different case,
+			 * there is no reason to check to see if the item
+			 * exists. If the local file system is case insensitive.
+			 */
+			if (!(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
+				check_dest_exist = False;
 		}
 	}
 
@@ -4307,33 +4315,41 @@ NTSTATUS rename_internals_fsp(connection
 		return NT_STATUS_OK;
 	}
 
-	dest_exists = vfs_object_exist(conn,newname,NULL);
-
-	if(!replace_if_exists && dest_exists) {
-		DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
-			fsp->fsp_name,newname));
-		return NT_STATUS_OBJECT_NAME_COLLISION;
-	}
+	/*
+	 * The check_dest_exist is only set to false when the the file system is case
+	 * insensitive and we are just renaming the item to a different case. No sense
+	 * checking to see if it exist in this case since we know it does. We will
+	 * just let the underlining file system handle the exist issues.
+	 */
+	if (check_dest_exist) {
+		dest_exists = vfs_object_exist(conn,newname,NULL);
 
-	/* 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);
+		if(!replace_if_exists && dest_exists) {
+			DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
+				fsp->fsp_name,newname));
+			return NT_STATUS_OBJECT_NAME_COLLISION;
 		}
-	} else {
-		if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
-			return map_nt_error_from_unix(errno);
+
+		/* 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);
+			}
 		}
-	}
 
-	status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+		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))
-			status = NT_STATUS_ACCESS_DENIED;
-		return status;
+		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))
+				status = NT_STATUS_ACCESS_DENIED;
+			return status;
+		}
 	}
 
 	if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
@@ -4456,6 +4472,7 @@ NTSTATUS rename_internals(connection_str
 	const char *dname;
 	long offset = 0;
 	pstring destname;
+	BOOL check_dest_exist = True;
 
 	*directory = *mask = 0;
 
@@ -4578,6 +4595,14 @@ NTSTATUS rename_internals(connection_str
 				 * the original.
 				 */
 				pstrcpy(p+1, last_component_dest);
+				/*
+				 * We are renaming the same item to a different
+				 * case, there is no reason to check to see if
+				 * the item exists. If the local file system is
+				 * case insensitive.
+				 */
+				if (!(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
+					check_dest_exist = False;
 			}
 		}
 	
@@ -4633,7 +4658,6 @@ NTSTATUS rename_internals(connection_str
 		 * If the src and dest names are identical - including case,
 		 * don't do the rename, just return success.
 		 */
-
 		if (strcsequal(directory, newname)) {
 			DEBUG(3, ("rename_internals: identical names in "
 				  "rename %s - returning success\n",
@@ -4641,7 +4665,20 @@ NTSTATUS rename_internals(connection_str
 			return NT_STATUS_OK;
 		}
 
-		if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
+
+		/*
+		 * We don't care if the item exist in the following cases:
+		 *
+		 * 1. They want us to replace the item even if it exist.
+		 *
+		 * 2. The check_dest_exist flag is set to false. This can only
+		 * happen when the file system is case insensitive and we are
+		 * just renaming the item to a different case. No sense
+		 * checking to see if it exist in this case since we know it
+		 * does. We will just let the underlining file system handle
+		 * the exist issues.
+		 */
+		if(check_dest_exist && !replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
 			DEBUG(3,("rename_internals: dest exists doing "
 				 "rename %s -> %s\n", directory, newname));
 			return NT_STATUS_OBJECT_NAME_COLLISION;