diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/locking/brlock.c | 73 | ||||
-rw-r--r-- | source3/smbd/files.c | 46 | ||||
-rw-r--r-- | 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 @@ -92,6 +92,28 @@ static BOOL brl_same_context(struct lock_context *ctx1, } /**************************************************************************** + 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; i<count; i++) { if (brl_conflict(&locks[i], &lock)) { - status = NT_STATUS_LOCK_NOT_GRANTED; + status = brl_lock_failed(&lock);; /* Did we block ourselves ? */ if (brl_same_context(&locks[i].context, &lock.context)) *my_lock_ctx = True; @@ -375,24 +422,16 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare); #endif - tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); + if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto fail; + } SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return NT_STATUS_OK; fail: - /* this is a nasty hack to try to simulate the lock result cache code in w2k. - It isn't completely accurate as I haven't yet worked out the correct - semantics (tridge) - */ - if (last_failed == fnum && - last_failed_start == start && - NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { - status = NT_STATUS_FILE_LOCK_CONFLICT; - } - last_failed = fnum; - last_failed_start = start; SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 80544c9a30..580dc54545 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -289,12 +289,12 @@ files_struct *file_find_fsp(files_struct *orig_fsp) { files_struct *fsp; - for (fsp=Files;fsp;fsp=fsp->next) { - 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. */ |