summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/smb.h2
-rw-r--r--source4/include/smb_interfaces.h4
-rw-r--r--source4/ntvfs/common/brlock.c418
-rw-r--r--source4/ntvfs/posix/config.mk4
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c151
-rw-r--r--source4/ntvfs/posix/pvfs_open.c19
-rw-r--r--source4/ntvfs/posix/pvfs_read.c9
-rw-r--r--source4/ntvfs/posix/pvfs_write.c17
-rw-r--r--source4/ntvfs/posix/vfs_posix.c28
-rw-r--r--source4/ntvfs/posix/vfs_posix.h21
-rw-r--r--source4/smbd/process_model.h2
-rw-r--r--source4/smbd/process_single.c2
-rw-r--r--source4/smbd/process_standard.c2
-rw-r--r--source4/smbd/process_thread.c2
-rw-r--r--source4/smbd/service.c6
-rw-r--r--source4/smbd/service.h15
16 files changed, 671 insertions, 31 deletions
diff --git a/source4/include/smb.h b/source4/include/smb.h
index 46b2dd03ca..745e90e4ff 100644
--- a/source4/include/smb.h
+++ b/source4/include/smb.h
@@ -611,6 +611,6 @@ typedef struct nt_user_token {
#define REQ_CONTROL_ASYNC (1<<2) /* the backend will answer this one later */
/* passed to br lock code */
-enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK};
+enum brl_type {READ_LOCK, WRITE_LOCK};
#endif /* _SMB_H */
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h
index 4acdf51b56..e9f51ba4d1 100644
--- a/source4/include/smb_interfaces.h
+++ b/source4/include/smb_interfaces.h
@@ -1450,7 +1450,9 @@ union smb_lock {
/* generic interface */
struct {
enum smb_lock_level level;
-
+ struct {
+ uint16_t fnum;
+ } in;
} generic;
/* SMBlock interface */
diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c
new file mode 100644
index 0000000000..0eb644e943
--- /dev/null
+++ b/source4/ntvfs/common/brlock.c
@@ -0,0 +1,418 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ generic byte range locking code
+
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Jeremy Allison 1992-2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This module implements a tdb based byte range locking service,
+ replacing the fcntl() based byte range locking previously
+ used. This allows us to provide the same semantics as NT */
+
+#include "includes.h"
+
+struct brl_context {
+ struct tdb_wrap *w;
+ servid_t server;
+ uint16_t tid;
+};
+
+/*
+ in this module a "DATA_BLOB *file_key" is a blob that uniquely identifies
+ a file. For a local posix filesystem this will usually be a combination
+ of the device and inode numbers of the file, but it can be anything
+ that uniquely idetifies a file for locking purposes, as long
+ as it is applied consistently.
+*/
+
+/*
+ the lock context contains the elements that define whether one
+ lock is the same as another lock
+*/
+struct lock_context {
+ servid_t server;
+ uint16_t smbpid;
+ uint16_t tid;
+};
+
+/* The data in brlock records is an unsorted linear array of these
+ records. It is unnecessary to store the count as tdb provides the
+ size of the record */
+struct lock_struct {
+ struct lock_context context;
+ uint64_t start;
+ uint64_t size;
+ uint16_t fnum;
+ enum brl_type lock_type;
+};
+
+/*
+ Open up the brlock.tdb database. Close it down using
+ talloc_free()
+*/
+void *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid)
+{
+ char *path;
+ struct brl_context *brl;
+
+ brl = talloc_p(mem_ctx, struct brl_context);
+ if (brl == NULL) {
+ return NULL;
+ }
+
+ path = lock_path(brl, "brlock.tdb");
+ brl->w = tdb_wrap_open(brl, path, 0,
+ TDB_DEFAULT|TDB_CLEAR_IF_FIRST,
+ O_RDWR|O_CREAT, 0600);
+ talloc_free(path);
+ if (brl->w == NULL) {
+ talloc_free(brl);
+ return NULL;
+ }
+
+ brl->server = server;
+ brl->tid = tid;
+
+ return (void *)brl;
+}
+
+
+/*
+ see if two locking contexts are equal
+*/
+static BOOL brl_same_context(struct lock_context *ctx1, struct lock_context *ctx2)
+{
+ return (ctx1->server == ctx2->server &&
+ ctx1->smbpid == ctx2->smbpid &&
+ ctx1->tid == ctx2->tid);
+}
+
+/*
+ See if lock2 can be added when lock1 is in place.
+*/
+static BOOL brl_conflict(struct lock_struct *lck1,
+ struct lock_struct *lck2)
+{
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+ return False;
+ }
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size)) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/*
+ Check to see if this lock conflicts, but ignore our own locks on the
+ same fnum only.
+*/
+static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
+{
+ if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
+ return False;
+
+ if (brl_same_context(&lck1->context, &lck2->context) &&
+ lck1->fnum == lck2->fnum) {
+ return False;
+ }
+
+ if (lck1->start >= (lck2->start + lck2->size) ||
+ lck2->start >= (lck1->start + lck1->size))
+ return False;
+
+ return True;
+}
+
+
+
+/*
+ Lock a range of bytes.
+*/
+NTSTATUS brl_lock(void *brl_ctx,
+ DATA_BLOB *file_key,
+ uint16_t smbpid,
+ uint16_t fnum,
+ uint64_t start, uint64_t size,
+ enum brl_type lock_type)
+{
+ struct brl_context *brl = brl_ctx;
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct lock, *locks;
+ char *tp;
+ NTSTATUS status;
+
+ kbuf.dptr = file_key->data;
+ kbuf.dsize = file_key->length;
+
+ if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ dbuf = tdb_fetch(brl->w->tdb, kbuf);
+
+ lock.context.smbpid = smbpid;
+ lock.context.server = brl->server;
+ lock.context.tid = brl->tid;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = fnum;
+ lock.lock_type = lock_type;
+
+ if (dbuf.dptr) {
+ /* there are existing locks - make sure they don't conflict */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ if (brl_conflict(&locks[i], &lock)) {
+ status = NT_STATUS_LOCK_NOT_GRANTED;
+ goto fail;
+ }
+ }
+ }
+
+ /* no conflicts - add it to the list of locks */
+ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
+ if (!tp) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ } else {
+ dbuf.dptr = tp;
+ }
+ memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
+ dbuf.dsize += sizeof(lock);
+
+ if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto fail;
+ }
+
+ free(dbuf.dptr);
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return NT_STATUS_OK;
+
+ fail:
+
+ free(dbuf.dptr);
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return status;
+}
+
+
+/*
+ Unlock a range of bytes.
+*/
+NTSTATUS brl_unlock(void *brl_ctx,
+ DATA_BLOB *file_key,
+ uint16_t smbpid,
+ uint16_t fnum,
+ uint64_t start, uint64_t size)
+{
+ struct brl_context *brl = brl_ctx;
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct *locks;
+ struct lock_context context;
+ NTSTATUS status;
+
+ kbuf.dptr = file_key->data;
+ kbuf.dsize = file_key->length;
+
+ if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ dbuf = tdb_fetch(brl->w->tdb, kbuf);
+ if (!dbuf.dptr) {
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return NT_STATUS_RANGE_NOT_LOCKED;
+ }
+
+ context.smbpid = smbpid;
+ context.server = brl->server;
+ context.tid = brl->tid;
+
+ /* there are existing locks - find a match */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (brl_same_context(&lock->context, &context) &&
+ lock->fnum == fnum &&
+ lock->start == start &&
+ lock->size == size) {
+ /* found it - delete it */
+ if (count == 1) {
+ if (tdb_delete(brl->w->tdb, kbuf) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto fail;
+ }
+ } else {
+ if (i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ dbuf.dsize -= sizeof(*locks);
+ if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto fail;
+ }
+ }
+
+ free(dbuf.dptr);
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* we didn't find it */
+ status = NT_STATUS_RANGE_NOT_LOCKED;
+
+ fail:
+ free(dbuf.dptr);
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return status;
+}
+
+
+/*
+ Test if we are allowed to perform IO on a region of an open file
+*/
+NTSTATUS brl_locktest(void *brl_ctx,
+ DATA_BLOB *file_key,
+ uint16_t fnum,
+ uint16 smbpid,
+ uint64_t start, uint64_t size,
+ enum brl_type lock_type)
+{
+ struct brl_context *brl = brl_ctx;
+ TDB_DATA kbuf, dbuf;
+ int count, i;
+ struct lock_struct lock, *locks;
+
+ kbuf.dptr = file_key->data;
+ kbuf.dsize = file_key->length;
+
+ dbuf = tdb_fetch(brl->w->tdb, kbuf);
+ if (dbuf.dptr == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ lock.context.smbpid = smbpid;
+ lock.context.server = brl->server;
+ lock.context.tid = brl->tid;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = fnum;
+ lock.lock_type = lock_type;
+
+ /* there are existing locks - make sure they don't conflict */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+
+ for (i=0; i<count; i++) {
+ if (brl_conflict_other(&locks[i], &lock)) {
+ free(dbuf.dptr);
+ return NT_STATUS_FILE_LOCK_CONFLICT;
+ }
+ }
+
+ free(dbuf.dptr);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ Remove any locks associated with a open file.
+*/
+NTSTATUS brl_close(void *brl_ctx,
+ DATA_BLOB *file_key, int fnum)
+{
+ struct brl_context *brl = brl_ctx;
+ TDB_DATA kbuf, dbuf;
+ int count, i, dcount=0;
+ struct lock_struct *locks;
+ NTSTATUS status;
+
+ kbuf.dptr = file_key->data;
+ kbuf.dsize = file_key->length;
+
+ if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ dbuf = tdb_fetch(brl->w->tdb, kbuf);
+ if (!dbuf.dptr) {
+ tdb_chainunlock(brl->w->tdb, kbuf);
+ return NT_STATUS_OK;
+ }
+
+ /* there are existing locks - remove any for this fnum */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->context.tid == brl->tid &&
+ lock->context.server == brl->server &&
+ lock->fnum == fnum) {
+ /* found it - delete it */
+ if (count > 1 && i < count-1) {
+ memmove(&locks[i], &locks[i+1],
+ sizeof(*locks)*((count-1) - i));
+ }
+ count--;
+ i--;
+ dcount++;
+ }
+ }
+
+ status = NT_STATUS_OK;
+
+ if (count == 0) {
+ if (tdb_delete(brl->w->tdb, kbuf) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ } else if (dcount != 0) {
+ dbuf.dsize -= dcount * sizeof(*locks);
+ if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ }
+
+ free(dbuf.dptr);
+ tdb_chainunlock(brl->w->tdb, kbuf);
+
+ return status;
+}
+
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk
index 019288faaa..8ca5ad7b0b 100644
--- a/source4/ntvfs/posix/config.mk
+++ b/source4/ntvfs/posix/config.mk
@@ -19,6 +19,8 @@ ADD_OBJ_FILES = \
ntvfs/posix/pvfs_setfileinfo.o \
ntvfs/posix/pvfs_rename.o \
ntvfs/posix/pvfs_resolve.o \
- ntvfs/posix/pvfs_shortname.o
+ ntvfs/posix/pvfs_shortname.o \
+ ntvfs/posix/pvfs_lock.o \
+ ntvfs/common/brlock.o
# End MODULE ntvfs_posix
################################################
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c
new file mode 100644
index 0000000000..d7aca9df8b
--- /dev/null
+++ b/source4/ntvfs/posix/pvfs_lock.c
@@ -0,0 +1,151 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ POSIX NTVFS backend - locking
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "include/includes.h"
+#include "vfs_posix.h"
+
+
+/*
+ check if we can perform IO on a range that might be locked
+*/
+NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs,
+ struct pvfs_file *f,
+ uint16_t smbpid,
+ uint64_t offset, uint64_t count,
+ enum brl_type rw)
+{
+ if (!(pvfs->flags & PVFS_FLAG_STRICT_LOCKING)) {
+ return NT_STATUS_OK;
+ }
+
+ return brl_locktest(pvfs->brl_context,
+ &f->locking_key,
+ f->fnum,
+ smbpid,
+ offset, count, rw);
+}
+
+/*
+ lock or unlock a byte range
+*/
+NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
+ struct smbsrv_request *req, union smb_lock *lck)
+{
+ struct pvfs_state *pvfs = ntvfs->private_data;
+ struct pvfs_file *f;
+ struct smb_lock_entry *locks;
+ int i;
+ enum brl_type rw;
+
+ f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum);
+ if (!f) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ switch (lck->generic.level) {
+ case RAW_LOCK_LOCK:
+ return brl_lock(pvfs->brl_context,
+ &f->locking_key,
+ req->smbpid,
+ f->fnum,
+ lck->lock.in.offset,
+ lck->lock.in.count,
+ WRITE_LOCK);
+
+ case RAW_LOCK_UNLOCK:
+ return brl_unlock(pvfs->brl_context,
+ &f->locking_key,
+ req->smbpid,
+ f->fnum,
+ lck->lock.in.offset,
+ lck->lock.in.count);
+
+ case RAW_LOCK_GENERIC:
+ return NT_STATUS_INVALID_LEVEL;
+
+ case RAW_LOCK_LOCKX:
+ /* fall through to the most complex case */
+ break;
+ }
+
+ /* now the lockingX case, most common and also most complex */
+
+ if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) {
+ rw = READ_LOCK;
+ } else {
+ rw = WRITE_LOCK;
+ }
+
+ if (lck->lockx.in.mode &
+ (LOCKING_ANDX_OPLOCK_RELEASE |
+ LOCKING_ANDX_CHANGE_LOCKTYPE |
+ LOCKING_ANDX_CANCEL_LOCK)) {
+ /* todo: need to add support for these */
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+
+ /* the unlocks happen first */
+ locks = lck->lockx.in.locks;
+
+ for (i=0;i<lck->lockx.in.ulock_cnt;i++) {
+ NTSTATUS status;
+ status = brl_unlock(pvfs->brl_context,
+ &f->locking_key,
+ locks[i].pid,
+ f->fnum,
+ locks[i].offset,
+ locks[i].count);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ locks += i;
+
+ for (i=0;i<lck->lockx.in.lock_cnt;i++) {
+ NTSTATUS status;
+
+ status = brl_lock(pvfs->brl_context,
+ &f->locking_key,
+ locks[i].pid,
+ f->fnum,
+ locks[i].offset,
+ locks[i].count,
+ rw);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* undo the locks we just did */
+ for (i=i-1;i>=0;i--) {
+ brl_unlock(pvfs->brl_context,
+ &f->locking_key,
+ locks[i].pid,
+ f->fnum,
+ locks[i].offset,
+ locks[i].count);
+ }
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 29e57e5a08..51526461e0 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -51,6 +51,9 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
static int pvfs_fd_destructor(void *p)
{
struct pvfs_file *f = p;
+
+ brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum);
+
if (f->fd != -1) {
close(f->fd);
f->fd = -1;
@@ -71,6 +74,10 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
struct pvfs_filename *name;
struct pvfs_file *f;
NTSTATUS status;
+ struct {
+ dev_t device;
+ ino_t inode;
+ } lock_context;
if (io->generic.level != RAW_OPEN_GENERIC) {
return ntvfs_map_open(req, io, ntvfs);
@@ -161,6 +168,13 @@ do_open:
f->name = talloc_steal(f, name);
f->session = req->session;
f->smbpid = req->smbpid;
+ f->pvfs = pvfs;
+
+ /* we must zero here to take account of padding */
+ ZERO_STRUCT(lock_context);
+ lock_context.device = name->st.st_dev;
+ lock_context.inode = name->st.st_ino;
+ f->locking_key = data_blob_talloc(f, &lock_context, sizeof(lock_context));
/* setup a destructor to avoid file descriptor leaks on
abnormal termination */
@@ -204,6 +218,11 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
+ status = brl_close(pvfs->brl_context, &f->locking_key, f->fnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
if (close(f->fd) != 0) {
status = pvfs_map_errno(pvfs, errno);
} else {
diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c
index e0c7e0b1f2..24142a81ee 100644
--- a/source4/ntvfs/posix/pvfs_read.c
+++ b/source4/ntvfs/posix/pvfs_read.c
@@ -32,6 +32,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
struct pvfs_state *pvfs = ntvfs->private_data;
ssize_t ret;
struct pvfs_file *f;
+ NTSTATUS status;
if (rd->generic.level != RAW_READ_READX) {
return NT_STATUS_NOT_SUPPORTED;
@@ -43,6 +44,14 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
+ status = pvfs_check_lock(pvfs, f, req->smbpid,
+ rd->readx.in.offset,
+ rd->readx.in.maxcnt,
+ READ_LOCK);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
ret = pread(f->fd,
rd->readx.out.data,
rd->readx.in.maxcnt,
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index a49f4fe947..80a3dae3a7 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -33,6 +33,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
struct pvfs_state *pvfs = ntvfs->private_data;
ssize_t ret;
struct pvfs_file *f;
+ NTSTATUS status;
switch (wr->generic.level) {
case RAW_WRITE_WRITEX:
@@ -40,6 +41,14 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
+ status = pvfs_check_lock(pvfs, f, req->smbpid,
+ wr->writex.in.offset,
+ wr->writex.in.count,
+ WRITE_LOCK);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
ret = pwrite(f->fd,
wr->writex.in.data,
wr->writex.in.count,
@@ -62,6 +71,14 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
/* a truncate! */
ret = ftruncate(f->fd, wr->write.in.offset);
} else {
+ status = pvfs_check_lock(pvfs, f, req->smbpid,
+ wr->write.in.offset,
+ wr->write.in.count,
+ WRITE_LOCK);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
ret = pwrite(f->fd,
wr->write.in.data,
wr->write.in.count,
diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c
index a17b90e369..5e7a605c9f 100644
--- a/source4/ntvfs/posix/vfs_posix.c
+++ b/source4/ntvfs/posix/vfs_posix.c
@@ -35,11 +35,12 @@ static void pvfs_setup_options(struct pvfs_state *pvfs)
{
int snum = pvfs->tcon->service;
- if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
- if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
- if (lp_map_system(snum)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
- if (lp_readonly(snum)) pvfs->flags |= PVFS_FLAG_READONLY;
- if (lp_strict_sync(snum)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
+ if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
+ if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
+ if (lp_map_system(snum)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
+ if (lp_readonly(snum)) pvfs->flags |= PVFS_FLAG_READONLY;
+ if (lp_strict_sync(snum)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
+ if (lp_strict_locking(snum)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
pvfs->share_name = talloc_strdup(pvfs, lp_servicename(snum));
}
@@ -86,6 +87,13 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
ntvfs->private_data = pvfs;
+ pvfs->brl_context = brl_init(pvfs,
+ pvfs->tcon->smb_conn->connection->server_id,
+ pvfs->tcon->service);
+ if (pvfs->brl_context == NULL) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
status = pvfs_mangle_init(pvfs);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -162,16 +170,6 @@ static NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs,
}
/*
- lock a byte range
-*/
-static NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
- struct smbsrv_request *req, union smb_lock *lck)
-{
- DEBUG(0,("pvfs_lock not implemented\n"));
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
-/*
set info on a pathname
*/
static NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 6819d01529..e83f0479a9 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -51,6 +51,8 @@ struct pvfs_state {
struct pvfs_file *open_files;
struct pvfs_mangle_context *mangle_ctx;
+
+ void *brl_context;
};
@@ -115,6 +117,12 @@ struct pvfs_file {
/* we need to remember the client pid that
opened the file so SMBexit works */
uint16_t smbpid;
+
+ /* a unique file key to be used for file locking */
+ DATA_BLOB locking_key;
+
+ /* we need this hook back to our parent for lock destruction */
+ struct pvfs_state *pvfs;
};
struct pvfs_mangle_context {
@@ -147,11 +155,12 @@ struct pvfs_mangle_context {
#define PVFS_RESOLVE_STREAMS (1<<1)
/* flags in pvfs->flags */
-#define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */
-#define PVFS_FLAG_MAP_ARCHIVE (1<<1)
-#define PVFS_FLAG_MAP_SYSTEM (1<<2)
-#define PVFS_FLAG_MAP_HIDDEN (1<<3)
-#define PVFS_FLAG_READONLY (1<<4)
-#define PVFS_FLAG_STRICT_SYNC (1<<5)
+#define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */
+#define PVFS_FLAG_MAP_ARCHIVE (1<<1)
+#define PVFS_FLAG_MAP_SYSTEM (1<<2)
+#define PVFS_FLAG_MAP_HIDDEN (1<<3)
+#define PVFS_FLAG_READONLY (1<<4)
+#define PVFS_FLAG_STRICT_SYNC (1<<5)
+#define PVFS_FLAG_STRICT_LOCKING (1<<6)
#endif /* _VFS_POSIX_H_ */
diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h
index 376b9a8ef8..79373d8a39 100644
--- a/source4/smbd/process_model.h
+++ b/source4/smbd/process_model.h
@@ -23,8 +23,6 @@
#ifndef SAMBA_PROCESS_MODEL_H
#define SAMBA_PROCESS_MODEL_H
-struct server_service_connection;
-
/* modules can use the following to determine if the interface has changed
* please increment the version number after each interface change
* with a comment and maybe update struct process_model_critical_sizes.
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index 12a265b62f..b96a1d0b2c 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -49,7 +49,7 @@ static void single_accept_connection(struct event_context *ev, struct fd_event *
return;
}
- conn = server_setup_connection(ev, server_socket, sock, t);
+ conn = server_setup_connection(ev, server_socket, sock, t, socket_get_fd(sock));
if (!conn) {
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
return;
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 122c6581b0..d70cfa676b 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -74,7 +74,7 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event
set_need_random_reseed();
- conn = server_setup_connection(ev, server_socket, sock, t);
+ conn = server_setup_connection(ev, server_socket, sock, t, getpid());
if (!conn) {
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
return;
diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c
index 55688f85e8..85f30c9ddd 100644
--- a/source4/smbd/process_thread.c
+++ b/source4/smbd/process_thread.c
@@ -79,7 +79,7 @@ static void thread_accept_connection(struct event_context *ev, struct fd_event *
return;
}
- conn = server_setup_connection(ev, server_socket, sock, t);
+ conn = server_setup_connection(ev, server_socket, sock, t, pthread_self());
if (!conn) {
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
event_context_destroy(ev);
diff --git a/source4/smbd/service.c b/source4/smbd/service.c
index 5aae84b2c9..9a7ac73559 100644
--- a/source4/smbd/service.c
+++ b/source4/smbd/service.c
@@ -198,7 +198,8 @@ static int server_destructor(void *ptr)
struct server_connection *server_setup_connection(struct event_context *ev,
struct server_socket *server_socket,
struct socket_context *sock,
- time_t t)
+ time_t t,
+ servid_t server_id)
{
struct fd_event fde;
struct timed_event idle;
@@ -206,7 +207,7 @@ struct server_connection *server_setup_connection(struct event_context *ev,
srv_conn = talloc_p(server_socket, struct server_connection);
if (!srv_conn) {
- DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n"));
+ DEBUG(0,("talloc_p(mem_ctx, struct server_connection) failed\n"));
return NULL;
}
@@ -229,6 +230,7 @@ struct server_connection *server_setup_connection(struct event_context *ev,
srv_conn->server_socket = server_socket;
srv_conn->service = server_socket->service;
srv_conn->socket = sock;
+ srv_conn->server_id = server_id;
/* create a smb server context and add it to out event
handling */
diff --git a/source4/smbd/service.h b/source4/smbd/service.h
index 88618964ce..e9ef0bff06 100644
--- a/source4/smbd/service.h
+++ b/source4/smbd/service.h
@@ -93,6 +93,19 @@ struct server_service {
struct server_context *srv_ctx;
};
+/* the concept of whether two operations are on the same server
+ connection or different connections is an important one in SMB, especially
+ for locking and share modes. We will use a servid_t to distinguish different
+ connections
+
+ this means that (for example) a unique open file is distinguished by the triple
+ of
+ servid_t server;
+ uint16 tid;
+ uint16 fnum;
+*/
+typedef uint32_t servid_t;
+
struct server_connection {
struct server_connection *next,*prev;
void *private_data;
@@ -104,6 +117,8 @@ struct server_connection {
time_t idle_time;
} event;
+ servid_t server_id;
+
struct socket_context *socket;
struct server_socket *server_socket;