2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1999
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 12 aug 96: Erik.Devriendt@te6.siemens.be
24 added support for shared memory implementation of share mode locking
26 May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27 locking to deal with multiple share modes per open file.
29 September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
32 rewrtten completely to use new tdb code. Tridge, Dec '99
36 extern int DEBUGLEVEL
;
38 /* the locking database handle */
39 static TDB_CONTEXT
*tdb
;
41 /****************************************************************************
42 Utility function to map a lock type correctly depending on the real open
44 ****************************************************************************/
45 static int map_lock_type(files_struct
*fsp
, int lock_type
)
47 if((lock_type
== F_WRLCK
) && (fsp
->fd_ptr
->real_open_flags
== O_RDONLY
)) {
49 * Many UNIX's cannot get a write lock on a file opened read-only.
50 * Win32 locking semantics allow this.
51 * Do the best we can and attempt a read-only lock.
53 DEBUG(10,("map_lock_type: Downgrading write lock to read due to read-only file.\n"));
55 } else if( (lock_type
== F_RDLCK
) && (fsp
->fd_ptr
->real_open_flags
== O_WRONLY
)) {
57 * Ditto for read locks on write only files.
59 DEBUG(10,("map_lock_type: Changing read lock to write due to write-only file.\n"));
64 * This return should be the most normal, as we attempt
65 * to always open files read/write.
71 /****************************************************************************
72 Utility function called to see if a file region is locked.
73 ****************************************************************************/
74 BOOL
is_locked(files_struct
*fsp
,connection_struct
*conn
,
75 SMB_OFF_T count
,SMB_OFF_T offset
, int lock_type
)
77 int snum
= SNUM(conn
);
82 if (!lp_locking(snum
) || !lp_strict_locking(snum
))
86 * Note that most UNIX's can *test* for a write lock on
87 * a read-only fd, just not *set* a write lock on a read-only
88 * fd. So we don't need to use map_lock_type here.
91 return(fcntl_lock(fsp
->fd_ptr
->fd
,SMB_F_GETLK
,offset
,count
,lock_type
));
95 /****************************************************************************
96 Utility function called by locking requests.
97 ****************************************************************************/
98 BOOL
do_lock(files_struct
*fsp
,connection_struct
*conn
,
99 SMB_OFF_T count
,SMB_OFF_T offset
,int lock_type
,
100 int *eclass
,uint32
*ecode
)
104 if (!lp_locking(SNUM(conn
)))
109 *ecode
= ERRnoaccess
;
113 DEBUG(10,("do_lock: lock type %d start=%.0f len=%.0f requested for file %s\n",
114 lock_type
, (double)offset
, (double)count
, fsp
->fsp_name
));
116 if (OPEN_FSP(fsp
) && fsp
->can_lock
&& (fsp
->conn
== conn
))
117 ok
= fcntl_lock(fsp
->fd_ptr
->fd
,SMB_F_SETLK
,offset
,count
,
118 map_lock_type(fsp
,lock_type
));
125 return True
; /* Got lock */
129 /****************************************************************************
130 Utility function called by unlocking requests.
131 ****************************************************************************/
132 BOOL
do_unlock(files_struct
*fsp
,connection_struct
*conn
,
133 SMB_OFF_T count
,SMB_OFF_T offset
,int *eclass
,uint32
*ecode
)
137 if (!lp_locking(SNUM(conn
)))
140 DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
141 (double)offset
, (double)count
, fsp
->fsp_name
));
143 if (OPEN_FSP(fsp
) && fsp
->can_lock
&& (fsp
->conn
== conn
))
144 ok
= fcntl_lock(fsp
->fd_ptr
->fd
,SMB_F_SETLK
,offset
,count
,F_UNLCK
);
151 return True
; /* Did unlock */
154 /****************************************************************************
155 Initialise the locking functions.
156 ****************************************************************************/
157 BOOL
locking_init(int read_only
)
159 if (tdb
) return True
;
161 tdb
= tdb_open(lock_path("locking.tdb"),
162 0, TDB_CLEAR_IF_FIRST
,
163 read_only
?O_RDONLY
:O_RDWR
|O_CREAT
,
167 DEBUG(0,("ERROR: Failed to initialise share modes\n"));
174 /*******************************************************************
175 Deinitialize the share_mode management.
176 ******************************************************************/
177 BOOL
locking_end(void)
179 if (tdb
&& tdb_close(tdb
) != 0) return False
;
183 /*******************************************************************
184 form a static locking key for a dev/inode pair
185 ******************************************************************/
186 static TDB_DATA
locking_key(SMB_DEV_T dev
, SMB_INO_T inode
)
188 static struct locking_key key
;
192 kbuf
.dptr
= (char *)&key
;
193 kbuf
.dsize
= sizeof(key
);
196 static TDB_DATA
locking_key_fsp(files_struct
*fsp
)
198 return locking_key(fsp
->fd_ptr
->dev
, fsp
->fd_ptr
->inode
);
201 /*******************************************************************
202 Lock a hash bucket entry.
203 ******************************************************************/
204 BOOL
lock_share_entry(connection_struct
*conn
,
205 SMB_DEV_T dev
, SMB_INO_T inode
)
207 return tdb_lockchain(tdb
, locking_key(dev
, inode
)) == 0;
210 /*******************************************************************
211 Unlock a hash bucket entry.
212 ******************************************************************/
213 BOOL
unlock_share_entry(connection_struct
*conn
,
214 SMB_DEV_T dev
, SMB_INO_T inode
)
216 return tdb_unlockchain(tdb
, locking_key(dev
, inode
)) == 0;
219 /*******************************************************************
220 Get all share mode entries for a dev/inode pair.
221 ********************************************************************/
222 int get_share_modes(connection_struct
*conn
,
223 SMB_DEV_T dev
, SMB_INO_T inode
,
224 share_mode_entry
**shares
)
227 struct locking_data
*data
;
232 dbuf
= tdb_fetch(tdb
, locking_key(dev
, inode
));
233 if (!dbuf
.dptr
) return 0;
235 data
= (struct locking_data
*)dbuf
.dptr
;
236 ret
= data
->num_share_mode_entries
;
237 *shares
= (share_mode_entry
*)memdup(dbuf
.dptr
+ sizeof(*data
), ret
* sizeof(**shares
));
240 if (! *shares
) return 0;
245 /*******************************************************************
246 Del the share mode of a file for this process
247 ********************************************************************/
248 void del_share_mode(files_struct
*fsp
)
251 struct locking_data
*data
;
253 share_mode_entry
*shares
;
254 pid_t pid
= getpid();
256 /* read in the existing share modes */
257 dbuf
= tdb_fetch(tdb
, locking_key_fsp(fsp
));
258 if (!dbuf
.dptr
) return;
260 data
= (struct locking_data
*)dbuf
.dptr
;
261 shares
= (share_mode_entry
*)(dbuf
.dptr
+ sizeof(*data
));
263 /* find any with our pid and delete it by overwriting with the rest of the data
265 for (i
=0;i
<data
->num_share_mode_entries
;) {
266 if (shares
[i
].pid
== pid
&&
267 memcmp(&shares
[i
].time
,
268 &fsp
->open_time
,sizeof(struct timeval
)) == 0) {
269 data
->num_share_mode_entries
--;
270 memmove(&shares
[i
], &shares
[i
+1],
271 dbuf
.dsize
- (sizeof(*data
) + (i
+1)*sizeof(*shares
)));
278 /* the record has shrunk a bit */
279 dbuf
.dsize
-= del_count
* sizeof(*shares
);
281 /* store it back in the database */
282 tdb_store(tdb
, locking_key_fsp(fsp
), dbuf
, TDB_REPLACE
);
287 /*******************************************************************
288 fill a share mode entry
289 ********************************************************************/
290 static void fill_share_mode(char *p
, files_struct
*fsp
, uint16 port
, uint16 op_type
)
292 share_mode_entry
*e
= (share_mode_entry
*)p
;
294 e
->share_mode
= fsp
->share_mode
;
296 e
->op_type
= op_type
;
297 memcpy((char *)&e
->time
, (char *)&fsp
->open_time
, sizeof(struct timeval
));
300 /*******************************************************************
301 Set the share mode of a file. Return False on fail, True on success.
302 ********************************************************************/
303 BOOL
set_share_mode(files_struct
*fsp
, uint16 port
, uint16 op_type
)
306 struct locking_data
*data
;
307 share_mode_entry
*shares
;
311 /* read in the existing share modes if any */
312 dbuf
= tdb_fetch(tdb
, locking_key_fsp(fsp
));
314 /* we'll need to create a new record */
317 pstrcpy(fname
, fsp
->conn
->connectpath
);
319 pstrcat(fname
, fsp
->fsp_name
);
321 size
= sizeof(*data
) + sizeof(*shares
) + strlen(fname
) + 1;
322 p
= (char *)malloc(size
);
323 data
= (struct locking_data
*)p
;
324 shares
= (share_mode_entry
*)(p
+ sizeof(*data
));
325 data
->num_share_mode_entries
= 1;
326 pstrcpy(p
+ sizeof(*data
) + sizeof(*shares
), fname
);
327 fill_share_mode(p
+ sizeof(*data
), fsp
, port
, op_type
);
330 tdb_store(tdb
, locking_key_fsp(fsp
), dbuf
, TDB_REPLACE
);
335 /* we're adding to an existing entry - this is a bit fiddly */
336 data
= (struct locking_data
*)dbuf
.dptr
;
337 shares
= (share_mode_entry
*)(dbuf
.dptr
+ sizeof(*data
));
339 data
->num_share_mode_entries
++;
340 size
= dbuf
.dsize
+ sizeof(*shares
);
342 memcpy(p
, dbuf
.dptr
, sizeof(*data
));
343 fill_share_mode(p
+ sizeof(*data
), fsp
, port
, op_type
);
344 memcpy(p
+ sizeof(*data
) + sizeof(*shares
), dbuf
.dptr
+ sizeof(*data
),
345 dbuf
.dsize
- sizeof(*data
));
349 tdb_store(tdb
, locking_key_fsp(fsp
), dbuf
, TDB_REPLACE
);
355 /*******************************************************************
356 a generic in-place modification call for share mode entries
357 ********************************************************************/
358 static BOOL
mod_share_mode(files_struct
*fsp
,
359 void (*mod_fn
)(share_mode_entry
*, SMB_DEV_T
, SMB_INO_T
, void *),
363 struct locking_data
*data
;
365 share_mode_entry
*shares
;
366 pid_t pid
= getpid();
369 /* read in the existing share modes */
370 dbuf
= tdb_fetch(tdb
, locking_key_fsp(fsp
));
371 if (!dbuf
.dptr
) return False
;
373 data
= (struct locking_data
*)dbuf
.dptr
;
374 shares
= (share_mode_entry
*)(dbuf
.dptr
+ sizeof(*data
));
376 /* find any with our pid and call the supplied function */
377 for (i
=0;i
<data
->num_share_mode_entries
;i
++) {
378 if (pid
== shares
[i
].pid
&&
379 shares
[i
].share_mode
== fsp
->share_mode
&&
380 memcmp(&shares
[i
].time
,
381 &fsp
->open_time
,sizeof(struct timeval
)) == 0) {
382 mod_fn(&shares
[i
], fsp
->fd_ptr
->dev
, fsp
->fd_ptr
->inode
, param
);
387 /* if the mod fn was called then store it back */
389 tdb_store(tdb
, locking_key_fsp(fsp
), dbuf
, TDB_REPLACE
);
397 /*******************************************************************
398 Static function that actually does the work for the generic function
400 ********************************************************************/
401 static void remove_share_oplock_fn(share_mode_entry
*entry
, SMB_DEV_T dev
, SMB_INO_T inode
,
404 DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
405 (unsigned int)dev
, (double)inode
));
406 /* Delete the oplock info. */
408 entry
->op_type
= NO_OPLOCK
;
411 /*******************************************************************
412 Remove an oplock port and mode entry from a share mode.
413 ********************************************************************/
414 BOOL
remove_share_oplock(files_struct
*fsp
)
416 return mod_share_mode(fsp
, remove_share_oplock_fn
, NULL
);
419 /*******************************************************************
420 Static function that actually does the work for the generic function
422 ********************************************************************/
423 static void downgrade_share_oplock_fn(share_mode_entry
*entry
, SMB_DEV_T dev
, SMB_INO_T inode
,
426 DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
427 (unsigned int)dev
, (double)inode
));
428 entry
->op_type
= LEVEL_II_OPLOCK
;
431 /*******************************************************************
432 Downgrade a oplock type from exclusive to level II.
433 ********************************************************************/
434 BOOL
downgrade_share_oplock(files_struct
*fsp
)
436 return mod_share_mode(fsp
, downgrade_share_oplock_fn
, NULL
);
440 /*******************************************************************
441 Static function that actually does the work for the generic function
443 ********************************************************************/
449 static void modify_share_mode_fn(share_mode_entry
*entry
, SMB_DEV_T dev
, SMB_INO_T inode
,
452 struct mod_val
*mvp
= (struct mod_val
*)param
;
454 DEBUG(10,("modify_share_mode_fn: changing share mode info from %x to %x for entry dev=%x ino=%.0f\n",
455 entry
->share_mode
, mvp
->new_share_mode
, (unsigned int)dev
, (double)inode
));
456 DEBUG(10,("modify_share_mode_fn: changing oplock state from %x to %x for entry dev=%x ino=%.0f\n",
457 entry
->op_type
, (int)mvp
->new_oplock
, (unsigned int)dev
, (double)inode
));
458 /* Change the share mode info. */
459 entry
->share_mode
= mvp
->new_share_mode
;
460 entry
->op_type
= mvp
->new_oplock
;
463 /*******************************************************************
464 Modify a share mode on a file. Used by the delete open file code.
465 Return False on fail, True on success.
466 ********************************************************************/
467 BOOL
modify_share_mode(files_struct
*fsp
, int new_mode
, uint16 new_oplock
)
471 mv
.new_share_mode
= new_mode
;
472 mv
.new_oplock
= new_oplock
;
474 return mod_share_mode(fsp
, modify_share_mode_fn
, (void *)&mv
);
477 static void (*traverse_callback
)(share_mode_entry
*, char *);
479 /****************************************************************************
480 traverse the whole database with this function, calling traverse_callback
482 ****************************************************************************/
483 static int traverse_fn(TDB_CONTEXT
*db
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
485 struct locking_data
*data
;
486 share_mode_entry
*shares
;
490 data
= (struct locking_data
*)dbuf
.dptr
;
491 shares
= (share_mode_entry
*)(dbuf
.dptr
+ sizeof(*data
));
492 name
= dbuf
.dptr
+ sizeof(*data
) + data
->num_share_mode_entries
*sizeof(*shares
);
494 for (i
=0;i
<data
->num_share_mode_entries
;i
++) {
495 traverse_callback(&shares
[i
], name
);
500 /*******************************************************************
501 Call the specified function on each entry under management by the
503 ********************************************************************/
504 int share_mode_forall(void (*fn
)(share_mode_entry
*, char *))
507 traverse_callback
= fn
;
508 return tdb_traverse(tdb
, traverse_fn
, NULL
);