summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/include/smb.h3
-rw-r--r--source3/locking/brlock.c73
-rw-r--r--source3/smbd/files.c46
-rw-r--r--source3/smbd/reply.c7
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.
*/