diff options
author | Jeremy Allison <jra@samba.org> | 2011-04-29 14:27:32 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2011-04-29 23:31:06 +0200 |
commit | 76739435fc8abf1f47193ec4db35a567b564c785 (patch) | |
tree | 77e3785a6f0adf2336f14d39f53cf02b49a593dc /source3/smbd | |
parent | bbacaec4e9365b128eb11467c95412de7473c1ec (diff) | |
download | samba-76739435fc8abf1f47193ec4db35a567b564c785.tar.gz |
Fix bug 8111 - CIFS VFS: unexpected error on SMB posix open
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
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/trans2.c | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index abab3879f6..028d3182a7 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -7286,18 +7286,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); |