r3012: added initial support for byte range locking in the posix vfs. This is
[bbaumbach/samba-autobuild/.git] / source4 / ntvfs / posix / pvfs_lock.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - locking
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "include/includes.h"
24 #include "vfs_posix.h"
25
26
27 /*
28   check if we can perform IO on a range that might be locked
29 */
30 NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs,
31                          struct pvfs_file *f,
32                          uint16_t smbpid,
33                          uint64_t offset, uint64_t count,
34                          enum brl_type rw)
35 {
36         if (!(pvfs->flags & PVFS_FLAG_STRICT_LOCKING)) {
37                 return NT_STATUS_OK;
38         }
39
40         return brl_locktest(pvfs->brl_context,
41                             &f->locking_key,
42                             f->fnum,
43                             smbpid,
44                             offset, count, rw);
45 }
46
47 /*
48   lock or unlock a byte range
49 */
50 NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
51                    struct smbsrv_request *req, union smb_lock *lck)
52 {
53         struct pvfs_state *pvfs = ntvfs->private_data;
54         struct pvfs_file *f;
55         struct smb_lock_entry *locks;
56         int i;
57         enum brl_type rw;
58
59         f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum);
60         if (!f) {
61                 return NT_STATUS_INVALID_HANDLE;
62         }
63
64         switch (lck->generic.level) {
65         case RAW_LOCK_LOCK:
66                 return brl_lock(pvfs->brl_context,
67                                 &f->locking_key,
68                                 req->smbpid,
69                                 f->fnum,
70                                 lck->lock.in.offset,
71                                 lck->lock.in.count,
72                                 WRITE_LOCK);
73                                 
74         case RAW_LOCK_UNLOCK:
75                 return brl_unlock(pvfs->brl_context,
76                                   &f->locking_key,
77                                   req->smbpid,
78                                   f->fnum,
79                                   lck->lock.in.offset,
80                                   lck->lock.in.count);
81
82         case RAW_LOCK_GENERIC:
83                 return NT_STATUS_INVALID_LEVEL;
84
85         case RAW_LOCK_LOCKX:
86                 /* fall through to the most complex case */
87                 break;
88         }
89
90         /* now the lockingX case, most common and also most complex */
91
92         if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) {
93                 rw = READ_LOCK;
94         } else {
95                 rw = WRITE_LOCK;
96         }
97
98         if (lck->lockx.in.mode & 
99             (LOCKING_ANDX_OPLOCK_RELEASE |
100              LOCKING_ANDX_CHANGE_LOCKTYPE |
101              LOCKING_ANDX_CANCEL_LOCK)) {
102                 /* todo: need to add support for these */
103                 return NT_STATUS_NOT_IMPLEMENTED;
104         }
105
106
107         /* the unlocks happen first */
108         locks = lck->lockx.in.locks;
109
110         for (i=0;i<lck->lockx.in.ulock_cnt;i++) {
111                 NTSTATUS status;
112                 status = brl_unlock(pvfs->brl_context,
113                                     &f->locking_key,
114                                     locks[i].pid,
115                                     f->fnum,
116                                     locks[i].offset,
117                                     locks[i].count);
118                 if (!NT_STATUS_IS_OK(status)) {
119                         return status;
120                 }
121         }
122
123         locks += i;
124
125         for (i=0;i<lck->lockx.in.lock_cnt;i++) {
126                 NTSTATUS status;
127
128                 status = brl_lock(pvfs->brl_context,
129                                   &f->locking_key,
130                                   locks[i].pid,
131                                   f->fnum,
132                                   locks[i].offset,
133                                   locks[i].count,
134                                   rw);
135                 if (!NT_STATUS_IS_OK(status)) {
136                         /* undo the locks we just did */
137                         for (i=i-1;i>=0;i--) {
138                                 brl_unlock(pvfs->brl_context,
139                                            &f->locking_key,
140                                            locks[i].pid,
141                                            f->fnum,
142                                            locks[i].offset,
143                                            locks[i].count);
144                         }
145                         return status;
146                 }
147         }
148
149         return NT_STATUS_OK;
150 }
151