summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2011-04-29 14:27:32 -0700
committerJeremy Allison <jra@samba.org>2011-04-29 23:31:06 +0200
commit76739435fc8abf1f47193ec4db35a567b564c785 (patch)
tree77e3785a6f0adf2336f14d39f53cf02b49a593dc
parentbbacaec4e9365b128eb11467c95412de7473c1ec (diff)
downloadsamba-76739435fc8abf1f47193ec4db35a567b564c785.tar.gz
samba-76739435fc8abf1f47193ec4db35a567b564c785.tar.bz2
samba-76739435fc8abf1f47193ec4db35a567b564c785.zip
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
-rw-r--r--source3/smbd/trans2.c61
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);