Fix bug 8111 - CIFS VFS: unexpected error on SMB posix open
authorJeremy Allison <jra@samba.org>
Fri, 29 Apr 2011 21:22:54 +0000 (14:22 -0700)
committerKarolin Seeger <kseeger@samba.org>
Tue, 14 Jun 2011 10:57:34 +0000 (12:57 +0200)
We are conflating the O_CREAT|O_EXCL with the O_TRUNC
processing, they need to be separate. We need to chose
using (O_CREAT|O_EXCL) first, then modify if O_TRUNC is
set. This needs two separate switch statements.

Jeremy
(cherry picked from commit 37823155157d735356e1f223b425252c956d8c04)

source3/smbd/trans2.c

index 1a171d84d1d4b9cd9ca8d3fd632d98d6aea27963..0d144213e0323f924ef1a45751489614f244b119 100644 (file)
@@ -7045,18 +7045,55 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
 
        wire_open_mode &= ~SMB_ACCMODE;
 
-       if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
-               create_disp = FILE_CREATE;
-       } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
-               create_disp = FILE_OVERWRITE_IF;
-       } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
-               create_disp = FILE_OPEN_IF;
-       } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
-               create_disp = FILE_OPEN;
-       } else {
-               DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
-                       (unsigned int)wire_open_mode ));
-               return NT_STATUS_INVALID_PARAMETER;
+       /* First take care of O_CREAT|O_EXCL interactions. */
+       switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
+               case (SMB_O_CREAT | SMB_O_EXCL):
+                       /* File exists fail. File not exist create. */
+                       create_disp = FILE_CREATE;
+                       break;
+               case SMB_O_CREAT:
+                       /* File exists open. File not exist create. */
+                       create_disp = FILE_OPEN_IF;
+                       break;
+               case 0:
+                       /* File exists open. File not exist fail. */
+                       create_disp = FILE_OPEN;
+                       break;
+               case SMB_O_EXCL:
+                       /* O_EXCL on its own without O_CREAT is undefined. */
+               default:
+                       DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
+                               (unsigned int)wire_open_mode ));
+                       return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* Next factor in the effects of O_TRUNC. */
+       wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
+
+       if (wire_open_mode & SMB_O_TRUNC) {
+               switch (create_disp) {
+                       case FILE_CREATE:
+                               /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
+                               /* Leave create_disp alone as
+                                  (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
+                               */
+                               /* File exists fail. File not exist create. */
+                               break;
+                       case FILE_OPEN_IF:
+                               /* SMB_O_CREAT | SMB_O_TRUNC */
+                               /* File exists overwrite. File not exist create. */
+                               create_disp = FILE_OVERWRITE_IF;
+                               break;
+                       case FILE_OPEN:
+                               /* SMB_O_TRUNC */
+                               /* File exists overwrite. File not exist fail. */
+                               create_disp = FILE_OVERWRITE;
+                               break;
+                       default:
+                               /* Cannot get here. */
+                               smb_panic("smb_posix_open: logic error");
+                               return NT_STATUS_INVALID_PARAMETER;
+               }
        }
 
        raw_unixmode = IVAL(pdata,8);