From 8c1c918c94b443c7154d535b1f99201dc1767f97 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 18 Oct 2004 22:01:10 +0000 Subject: r3050: Steal from Samba4 :-). Make us pass most of the new lock tests (except for the cancel lock which I have to add). Jeremy. (This used to be commit cf7f89999e0c6becd4617c812400d1e71b9c0a30) --- source3/include/smb.h | 3 +- source3/locking/brlock.c | 73 +++++++++++++++++++++++++++++++++++++----------- source3/smbd/files.c | 46 +++++++++++++++--------------- source3/smbd/reply.c | 7 ++++- 4 files changed, 87 insertions(+), 42 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 7317fd16b0..bc99a2a6fd 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -380,8 +380,7 @@ typedef struct #include "fake_file.h" -typedef struct files_struct -{ +typedef struct files_struct { struct files_struct *next, *prev; int fnum; struct connection_struct *conn; diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 4c34bd7dfd..61144eb59a 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -91,6 +91,28 @@ static BOOL brl_same_context(struct lock_context *ctx1, (ctx1->tid == ctx2->tid); } +/**************************************************************************** + See if lck1 and lck2 overlap. +****************************************************************************/ + +static BOOL brl_overlap(struct lock_struct *lck1, + struct lock_struct *lck2) +{ + /* this extra check is not redundent - it copes with locks + that go beyond the end of 64 bit file space */ + if (lck1->size != 0 && + lck1->start == lck2->start && + lck1->size == lck2->size) { + return True; + } + + if (lck1->start >= (lck2->start+lck2->size) || + lck2->start >= (lck1->start+lck1->size)) { + return False; + } + return True; +} + /**************************************************************************** See if lock2 can be added when lock1 is in place. ****************************************************************************/ @@ -115,7 +137,7 @@ static BOOL brl_conflict(struct lock_struct *lck1, return False; } - return True; + return brl_overlap(lck1, lck2); } #if ZERO_ZERO @@ -175,9 +197,36 @@ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck lck2->start >= (lck1->start + lck1->size)) return False; - return True; + return brl_overlap(lck1, lck2); } +/**************************************************************************** + Amazingly enough, w2k3 "remembers" whether the last lock failure + is the same as this one and changes its error code. I wonder if any + app depends on this ? +****************************************************************************/ + +static NTSTATUS brl_lock_failed(struct lock_struct *lock) +{ + static struct lock_struct last_lock_failure; + + if (brl_same_context(&lock->context, &last_lock_failure.context) && + lock->fnum == last_lock_failure.fnum && + lock->start == last_lock_failure.start && + lock->size == last_lock_failure.size) { + return NT_STATUS_FILE_LOCK_CONFLICT; + } + last_lock_failure = *lock; + if (lock->start >= 0xEF000000 && + (lock->start >> 63) == 0) { + /* amazing the little things you learn with a test + suite. Locks beyond this offset (as a 64 bit + number!) always generate the conflict error code, + unless the top bit is set */ + return NT_STATUS_FILE_LOCK_CONFLICT; + } + return NT_STATUS_LOCK_NOT_GRANTED; +} #if DONT_DO_THIS /* doing this traversal could kill solaris machines under high load (tridge) */ @@ -313,8 +362,6 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, struct lock_struct lock, *locks; char *tp; NTSTATUS status = NT_STATUS_OK; - static int last_failed = -1; - static br_off last_failed_start; *my_lock_ctx = False; kbuf = locking_key(dev,ino); @@ -344,7 +391,7 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, count = dbuf.dsize / sizeof(*locks); for (i=0; inext) { - if (fsp == orig_fsp) - return fsp; - } + for (fsp=Files;fsp;fsp=fsp->next) { + if (fsp == orig_fsp) + return fsp; + } - return NULL; + return NULL; } /**************************************************************************** @@ -303,16 +303,16 @@ files_struct *file_find_fsp(files_struct *orig_fsp) files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) { - files_struct *fsp; + files_struct *fsp; - for (fsp=Files;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && - fsp->dev == dev && - fsp->inode == inode ) - return fsp; - } + for (fsp=Files;fsp;fsp=fsp->next) { + if ( fsp->fd != -1 && + fsp->dev == dev && + fsp->inode == inode ) + return fsp; + } - return NULL; + return NULL; } /**************************************************************************** @@ -321,16 +321,16 @@ files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) files_struct *file_find_di_next(files_struct *start_fsp) { - files_struct *fsp; + files_struct *fsp; - for (fsp = start_fsp->next;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && - fsp->dev == start_fsp->dev && - fsp->inode == start_fsp->inode ) - return fsp; - } + for (fsp = start_fsp->next;fsp;fsp=fsp->next) { + if ( fsp->fd != -1 && + fsp->dev == start_fsp->dev && + fsp->inode == start_fsp->inode ) + return fsp; + } - return NULL; + return NULL; } /**************************************************************************** @@ -388,7 +388,9 @@ void file_free(files_struct *fsp) information */ ZERO_STRUCTP(fsp); - if (fsp == chain_fsp) chain_fsp = NULL; + if (fsp == chain_fsp) { + chain_fsp = NULL; + } SAFE_FREE(fsp); } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index cdf607e273..845f058867 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -4514,13 +4514,18 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, data = smb_buf(inbuf); - if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) { + if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) { /* we don't support these - and CANCEL_LOCK makes w2k and XP reboot so I don't really want to be compatible! (tridge) */ return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + /* Need to make this like a cancel.... JRA. */ + return ERROR_NT(NT_STATUS_UNSUCCESSFUL); + } + /* Check if this is an oplock break on a file we have granted an oplock on. */ -- cgit