This commit was manufactured by cvs2svn to create tag
[Samba/gbeck.git] / source / locking / locking.c
blobce96aa01cf35bb1f0d830cfcdcce15ae7c30aa8c
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Locking functions
5 Copyright (C) Andrew Tridgell 1992-1996
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.
21 Revision History:
23 12 aug 96: Erik.Devriendt@te6.siemens.be
24 added support for shared memory implementation of share mode locking
27 #include "includes.h"
28 extern int DEBUGLEVEL;
29 extern connection_struct Connections[];
30 extern files_struct Files[];
32 pstring share_del_pending="";
35 /****************************************************************************
36 utility function called to see if a file region is locked
37 ****************************************************************************/
38 BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
40 int snum = SNUM(cnum);
42 if (count == 0)
43 return(False);
45 if (!lp_locking(snum) || !lp_strict_locking(snum))
46 return(False);
48 return(fcntl_lock(Files[fnum].fd_ptr->fd,F_GETLK,offset,count,
49 (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
53 /****************************************************************************
54 utility function called by locking requests
55 ****************************************************************************/
56 BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
58 BOOL ok = False;
60 if (!lp_locking(SNUM(cnum)))
61 return(True);
63 if (count == 0) {
64 *eclass = ERRDOS;
65 *ecode = ERRnoaccess;
66 return False;
69 if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
70 ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,
71 (Files[fnum].can_write?F_WRLCK:F_RDLCK));
73 if (!ok) {
74 *eclass = ERRDOS;
75 *ecode = ERRlock;
76 return False;
78 return True; /* Got lock */
82 /****************************************************************************
83 utility function called by unlocking requests
84 ****************************************************************************/
85 BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
87 BOOL ok = False;
89 if (!lp_locking(SNUM(cnum)))
90 return(True);
92 if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
93 ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,F_UNLCK);
95 if (!ok) {
96 *eclass = ERRDOS;
97 *ecode = ERRlock;
98 return False;
100 return True; /* Did unlock */
103 #if FAST_SHARE_MODES
104 /*******************************************************************
105 initialize the shared memory for share_mode management
106 ******************************************************************/
107 BOOL start_share_mode_mgmt(void)
109 pstring shmem_file_name;
111 strcpy(shmem_file_name,lp_lockdir());
112 if (!directory_exist(shmem_file_name,NULL))
113 mkdir(shmem_file_name,0755);
114 trim_string(shmem_file_name,"","/");
115 if (!*shmem_file_name) return(False);
116 strcat(shmem_file_name, "/SHARE_MEM_FILE");
117 return smb_shm_open(shmem_file_name, SHMEM_SIZE);
121 /*******************************************************************
122 deinitialize the shared memory for share_mode management
123 ******************************************************************/
124 BOOL stop_share_mode_mgmt(void)
126 return smb_shm_close();
129 #else
131 /* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
133 /*******************************************************************
134 name a share file
135 ******************************************************************/
136 static BOOL share_name(int cnum,struct stat *st,char *name)
138 strcpy(name,lp_lockdir());
139 standard_sub(cnum,name);
140 trim_string(name,"","/");
141 if (!*name) return(False);
142 name += strlen(name);
144 sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
145 return(True);
148 /*******************************************************************
149 use the fnum to get the share file name
150 ******************************************************************/
151 static BOOL share_name_fnum(int fnum,char *name)
153 struct stat st;
154 if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
155 return(share_name(Files[fnum].cnum,&st,name));
158 #endif
160 /*******************************************************************
161 get the share mode of a file using the fnum
162 ******************************************************************/
163 int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
165 struct stat sbuf;
166 if (fstat(Files[fnum].fd_ptr->fd,&sbuf) == -1) return(0);
167 return(get_share_mode(cnum,&sbuf,pid));
170 /*******************************************************************
171 get the share mode of a file using the files name
172 ******************************************************************/
173 int get_share_mode_byname(int cnum,char *fname,int *pid)
175 struct stat sbuf;
176 if (stat(fname,&sbuf) == -1) return(0);
177 return(get_share_mode(cnum,&sbuf,pid));
181 /*******************************************************************
182 get the share mode of a file
183 ********************************************************************/
184 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
186 #if FAST_SHARE_MODES
187 share_mode_record *scanner_p;
188 share_mode_record *prev_p;
189 int ret;
190 BOOL found = False;
192 *pid = 0;
194 if(!smb_shm_lock()) return (0);
196 scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
197 prev_p = scanner_p;
198 while(scanner_p)
200 if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) )
202 found = True;
203 break;
205 else
207 prev_p = scanner_p ;
208 scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
212 if(!found)
214 smb_shm_unlock();
215 return (0);
218 if(scanner_p->locking_version != LOCKING_VERSION)
220 DEBUG(2,("Deleting old share mode record due to old locking version %d",scanner_p->locking_version));
221 if(prev_p == scanner_p)
222 smb_shm_set_userdef_off(scanner_p->next_offset);
223 else
224 prev_p->next_offset = scanner_p->next_offset;
225 smb_shm_free(smb_shm_addr2offset(scanner_p));
226 *pid = 0;
228 smb_shm_unlock();
229 return (0);
232 *pid = scanner_p->pid;
233 ret = scanner_p->share_mode;
235 if (*pid && !process_exists(*pid))
237 ret = 0;
238 *pid = 0;
241 if (! *pid)
243 if(prev_p == scanner_p)
244 smb_shm_set_userdef_off(scanner_p->next_offset);
245 else
246 prev_p->next_offset = scanner_p->next_offset;
247 smb_shm_free(smb_shm_addr2offset(scanner_p));
250 if (*pid)
251 DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid));
253 if(!smb_shm_unlock()) return (0);
255 return(ret);
257 #else
258 pstring fname;
259 int fd2;
260 char buf[20];
261 int ret;
262 struct timeval t;
264 *pid = 0;
266 if (!share_name(cnum,sbuf,fname)) return(0);
268 fd2 = open(fname,O_RDONLY,0);
269 if (fd2 < 0) return(0);
271 if (read(fd2,buf,20) != 20) {
272 DEBUG(2,("Failed to read share file %s\n",fname));
273 close(fd2);
274 unlink(fname);
275 return(0);
277 close(fd2);
279 t.tv_sec = IVAL(buf,4);
280 t.tv_usec = IVAL(buf,8);
281 ret = IVAL(buf,12);
282 *pid = IVAL(buf,16);
284 if (IVAL(buf,0) != LOCKING_VERSION) {
285 if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
286 *pid = 0;
287 return(0);
290 if (*pid && !process_exists(*pid)) {
291 ret=0;
292 *pid = 0;
295 if (! *pid) unlink(fname); /* XXXXX race, race */
297 if (*pid)
298 DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
300 return(ret);
301 #endif
305 /*******************************************************************
306 del the share mode of a file, if we set it last
307 ********************************************************************/
308 void del_share_mode(int fnum)
310 #if FAST_SHARE_MODES
311 struct stat st;
312 struct timeval t;
313 int pid=0;
314 BOOL del = False;
315 share_mode_record *scanner_p;
316 share_mode_record *prev_p;
317 BOOL found = False;
319 t.tv_sec = t.tv_usec = 0;
321 if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return;
323 if (!smb_shm_lock()) return;
325 scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
326 prev_p = scanner_p;
327 while(scanner_p)
329 if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
331 found = True;
332 break;
334 else
336 prev_p = scanner_p ;
337 scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
341 if(!found)
343 smb_shm_unlock();
344 return;
347 t.tv_sec = scanner_p->time.tv_sec;
348 t.tv_usec = scanner_p->time.tv_usec;
349 pid = scanner_p->pid;
351 if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
352 del = True;
354 if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0)
355 && pid==(int)getpid())
356 del = True;
358 if (del)
360 DEBUG(2,("Deleting share mode record\n"));
361 if(prev_p == scanner_p)
362 smb_shm_set_userdef_off(scanner_p->next_offset);
363 else
364 prev_p->next_offset = scanner_p->next_offset;
365 smb_shm_free(smb_shm_addr2offset(scanner_p));
369 smb_shm_unlock();
370 return;
372 #else
373 pstring fname;
374 int fd2;
375 char buf[20];
376 struct timeval t;
377 int pid=0;
378 BOOL del = False;
380 t.tv_sec = t.tv_usec = 0;
381 if (!share_name_fnum(fnum,fname)) return;
383 fd2 = open(fname,O_RDONLY,0);
384 if (fd2 < 0) return;
385 if (read(fd2,buf,20) != 20)
386 del = True;
387 close(fd2);
389 if (!del) {
390 t.tv_sec = IVAL(buf,4);
391 t.tv_usec = IVAL(buf,8);
392 pid = IVAL(buf,16);
395 if (!del)
396 if (IVAL(buf,0) != LOCKING_VERSION || !pid || !process_exists(pid))
397 del = True;
399 if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0) && (pid==(int)getpid()))
400 del = True;
402 if (del) {
403 if (!unlink(fname))
404 DEBUG(2,("Deleted share file %s\n",fname));
405 else {
406 DEBUG(3,("Pending delete share file %s\n",fname));
407 if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
408 strcpy(share_del_pending,fname);
411 #endif
415 /*******************************************************************
416 set the share mode of a file
417 ********************************************************************/
418 BOOL set_share_mode(int fnum,int mode)
420 #if FAST_SHARE_MODES
421 int pid = (int)getpid();
422 struct stat st;
423 smb_shm_offset_t new_off;
424 share_mode_record *new_p;
427 if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
429 if (!smb_shm_lock()) return (False);
430 new_off = smb_shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
431 if (new_off == NULL_OFFSET) return (False);
432 new_p = (share_mode_record *)smb_shm_offset2addr(new_off);
433 new_p->locking_version = LOCKING_VERSION;
434 new_p->share_mode = mode;
435 new_p->time.tv_sec = Files[fnum].open_time.tv_sec;
436 new_p->time.tv_usec = Files[fnum].open_time.tv_usec;
437 new_p->pid = pid;
438 new_p->st_dev = st.st_dev;
439 new_p->st_ino = st.st_ino;
440 strcpy(new_p->file_name,Files[fnum].name);
441 new_p->next_offset = smb_shm_get_userdef_off();
442 smb_shm_set_userdef_off(new_off);
445 DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
447 if (!smb_shm_unlock()) return (False);
448 return(True);
450 #else
451 pstring fname;
452 int fd2;
453 char buf[20];
454 int pid = (int)getpid();
456 if (!share_name_fnum(fnum,fname)) return(False);
459 int old_umask = umask(0);
460 fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
461 umask(old_umask);
463 if (fd2 < 0) {
464 DEBUG(2,("Failed to create share file %s\n",fname));
465 return(False);
468 SIVAL(buf,0,LOCKING_VERSION);
469 SIVAL(buf,4,Files[fnum].open_time.tv_sec);
470 SIVAL(buf,8,Files[fnum].open_time.tv_usec);
471 SIVAL(buf,12,mode);
472 SIVAL(buf,16,pid);
474 if (write(fd2,buf,20) != 20) {
475 DEBUG(2,("Failed to write share file %s\n",fname));
476 close(fd2);
477 unlink(fname);
478 return(False);
481 write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
483 close(fd2);
485 DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
487 return(True);
488 #endif
492 /*******************************************************************
493 cleanup any stale share files
494 ********************************************************************/
495 void clean_share_modes(void)
497 #ifdef USE_SHMEM
498 share_mode_record *scanner_p;
499 share_mode_record *prev_p;
500 int pid;
502 if (!smb_shm_lock()) return;
504 scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
505 prev_p = scanner_p;
506 while(scanner_p)
508 pid = scanner_p->pid;
510 if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
512 DEBUG(2,("Deleting stale share mode record"));
513 if(prev_p == scanner_p)
515 smb_shm_set_userdef_off(scanner_p->next_offset);
516 smb_shm_free(smb_shm_addr2offset(scanner_p));
517 scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
518 prev_p = scanner_p;
520 else
522 prev_p->next_offset = scanner_p->next_offset;
523 smb_shm_free(smb_shm_addr2offset(scanner_p));
524 scanner_p = (share_mode_record *)smb_shm_offset2addr(prev_p->next_offset);
528 else
530 prev_p = scanner_p ;
531 scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
536 smb_shm_unlock();
537 return;
539 #else
540 char *lockdir = lp_lockdir();
541 void *dir;
542 char *s;
544 if (!*lockdir) return;
546 dir = opendir(lockdir);
547 if (!dir) return;
549 while ((s=readdirname(dir))) {
550 char buf[20];
551 int pid;
552 int fd;
553 pstring lname;
554 int dev,inode;
556 if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
558 strcpy(lname,lp_lockdir());
559 trim_string(lname,NULL,"/");
560 strcat(lname,"/");
561 strcat(lname,s);
563 fd = open(lname,O_RDONLY,0);
564 if (fd < 0) continue;
566 if (read(fd,buf,20) != 20) {
567 close(fd);
568 if (!unlink(lname))
569 printf("Deleted corrupt share file %s\n",s);
570 continue;
572 close(fd);
574 pid = IVAL(buf,16);
576 if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) {
577 if (!unlink(lname))
578 printf("Deleted stale share file %s\n",s);
582 closedir(dir);
583 #endif