r3012: added initial support for byte range locking in the posix vfs. This is
authorAndrew Tridgell <tridge@samba.org>
Sun, 17 Oct 2004 02:55:47 +0000 (02:55 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:59:57 +0000 (12:59 -0500)
enough for us to pass locktest, but does not yet support lock timeouts
and some of the other esoteric features.
(This used to be commit 58a92abd88f190bc60894a68e0528e95ae33fe39)

16 files changed:
source4/include/smb.h
source4/include/smb_interfaces.h
source4/ntvfs/common/brlock.c [new file with mode: 0644]
source4/ntvfs/posix/config.mk
source4/ntvfs/posix/pvfs_lock.c [new file with mode: 0644]
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_read.c
source4/ntvfs/posix/pvfs_write.c
source4/ntvfs/posix/vfs_posix.c
source4/ntvfs/posix/vfs_posix.h
source4/smbd/process_model.h
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/process_thread.c
source4/smbd/service.c
source4/smbd/service.h

index 46b2dd03ca71fbe783626704a06d57914f3250da..745e90e4ff224b6987d4344e32d69075b88f11fd 100644 (file)
@@ -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 */
index 4acdf51b56409a34ffe6719e2199bcfcc4d16342..e9f51ba4d1a832646a6ab2a688af30053197ec47 100644 (file)
@@ -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 (file)
index 0000000..0eb644e
--- /dev/null
@@ -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;
+}
+
index 019288faaae6f5c4d13949333b9ce003a858fab8..8ca5ad7b0b3b2f99c53223dac192dd3574eee8bd 100644 (file)
@@ -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 (file)
index 0000000..d7aca9d
--- /dev/null
@@ -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;
+}
+
index 29e57e5a0821255d43f12de3904113db08943527..51526461e00657edeb1c568bd0f1559eee673e9e 100644 (file)
@@ -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 {
index e0c7e0b1f201279e609a76024cd2f87a221f1f50..24142a81ee79a51605f5b121791a9716d2177358 100644 (file)
@@ -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,
index a49f4fe9476d421b034f26ff8993b6f4534d192b..80a3dae3a700de662672e1bd710bba7307904433 100644 (file)
@@ -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,
index a17b90e3697ba156c6042f7e5bdf26822339b25d..5e7a605c9fa81071d197d1a2d48e9ce029fdbe28 100644 (file)
@@ -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;
@@ -161,16 +169,6 @@ static NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs,
        return NT_STATUS_NOT_SUPPORTED;
 }
 
-/*
-  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
 */
index 6819d01529d23b60dfcfa29c02c188c27ff4bb08..e83f0479a9164de254e77dbd565149536216fd34 100644 (file)
@@ -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_ */
index 376b9a8ef89e6e27580da21f84504c36a4b2e446..79373d8a39d7f7a148d252ec7fe1451362e3d35b 100644 (file)
@@ -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.
index 12a265b62f1213338e7004cf30274bb4434d0c4d..b96a1d0b2cb5d8d8634ff6b05626d66cdd5e9d7b 100644 (file)
@@ -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;
index 122c6581b0ce541b95e69eb28c8153f4d596218a..d70cfa676b01fd2dc78c06d9ab79ad00c7992b68 100644 (file)
@@ -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;
index 55688f85e86bc25147321b2493eafe06d2436b2d..85f30c9ddd773fd2ece5ade99a9c0bed0f25abbd 100644 (file)
@@ -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);
index 5aae84b2c94ff3b33dc352eed9d78972634334b2..9a7ac7355915c03c74df54ffdd5ebc3f9dba98fb 100644 (file)
@@ -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 */
index 88618964ceb1a61a6a58f475c322872b367d296a..e9ef0bff06e832c65924c1b8be8243334cd2698e 100644 (file)
@@ -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;