patch to fix NetServerEnum with multiple workgroup lists kindly supplied.
[Samba.git] / source / locking / locking.c
blob78661d6970681a2a9dd3f8eb367f981128ee6a23
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.
22 #include "includes.h"
23 extern int DEBUGLEVEL;
24 extern connection_struct Connections[];
25 extern files_struct Files[];
27 pstring share_del_pending="";
30 /****************************************************************************
31 routine to do file locking
32 ****************************************************************************/
33 BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
35 #if HAVE_FCNTL_LOCK
36 struct flock lock;
37 int ret;
39 #if 1
40 uint32 mask = 0xC0000000;
42 /* make sure the count is reasonable, we might kill the lockd otherwise */
43 count &= ~mask;
45 /* the offset is often strange - remove 2 of its bits if either of
46 the top two bits are set. Shift the top ones by two bits. This
47 still allows OLE2 apps to operate, but should stop lockd from
48 dieing */
49 if ((offset & mask) != 0)
50 offset = (offset & ~mask) | ((offset & mask) >> 2);
51 #else
52 unsigned long mask = ((unsigned)1<<31);
54 /* interpret negative counts as large numbers */
55 if (count < 0)
56 count &= ~mask;
58 /* no negative offsets */
59 offset &= ~mask;
61 /* count + offset must be in range */
62 while ((offset < 0 || (offset + count < 0)) && mask)
64 offset &= ~mask;
65 mask = mask >> 1;
67 #endif
70 DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
72 lock.l_type = type;
73 lock.l_whence = SEEK_SET;
74 lock.l_start = (int)offset;
75 lock.l_len = (int)count;
76 lock.l_pid = 0;
78 errno = 0;
80 ret = fcntl(fd,op,&lock);
82 if (errno != 0)
83 DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
85 /* a lock query */
86 if (op == F_GETLK)
88 if ((ret != -1) &&
89 (lock.l_type != F_UNLCK) &&
90 (lock.l_pid != 0) &&
91 (lock.l_pid != getpid()))
93 DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
94 return(True);
97 /* it must be not locked or locked by me */
98 return(False);
101 /* a lock set or unset */
102 if (ret == -1)
104 DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
105 offset,count,op,type,strerror(errno)));
107 /* perhaps it doesn't support this sort of locking?? */
108 if (errno == EINVAL)
110 DEBUG(3,("locking not supported? returning True\n"));
111 return(True);
114 return(False);
117 /* everything went OK */
118 DEBUG(5,("Lock call successful\n"));
120 return(True);
121 #else
122 return(False);
123 #endif
126 /*******************************************************************
127 lock a file - returning a open file descriptor or -1 on failure
128 The timeout is in seconds. 0 means no timeout
129 ********************************************************************/
130 int file_lock(char *name,int timeout)
132 int fd = open(name,O_RDWR|O_CREAT,0666);
133 time_t t=0;
134 if (fd < 0) return(-1);
136 #if HAVE_FCNTL_LOCK
137 if (timeout) t = time(NULL);
138 while (!timeout || (time(NULL)-t < timeout)) {
139 if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
140 msleep(LOCK_RETRY_TIMEOUT);
142 return(-1);
143 #else
144 return(fd);
145 #endif
148 /*******************************************************************
149 unlock a file locked by file_lock
150 ********************************************************************/
151 void file_unlock(int fd)
153 if (fd<0) return;
154 #if HAVE_FCNTL_LOCK
155 fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
156 #endif
157 close(fd);
161 /****************************************************************************
162 utility function called to see if a file region is locked
163 ****************************************************************************/
164 BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
166 int snum = SNUM(cnum);
168 if (count == 0)
169 return(False);
171 if (!lp_locking(snum) || !lp_strict_locking(snum))
172 return(False);
174 return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
175 (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
179 /****************************************************************************
180 utility function called by locking requests
181 ****************************************************************************/
182 BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
184 BOOL ok = False;
186 if (!lp_locking(SNUM(cnum)))
187 return(True);
189 if (count == 0) {
190 *eclass = ERRDOS;
191 *ecode = ERRnoaccess;
192 return False;
195 if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
196 ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
197 (Files[fnum].can_write?F_WRLCK:F_RDLCK));
199 if (!ok) {
200 *eclass = ERRDOS;
201 *ecode = ERRlock;
202 return False;
204 return True; /* Got lock */
208 /****************************************************************************
209 utility function called by unlocking requests
210 ****************************************************************************/
211 BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
213 BOOL ok = False;
215 if (!lp_locking(SNUM(cnum)))
216 return(True);
218 if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
219 ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
221 if (!ok) {
222 *eclass = ERRDOS;
223 *ecode = ERRlock;
224 return False;
226 return True; /* Did unlock */
229 /*******************************************************************
230 name a share file
231 ******************************************************************/
232 static BOOL share_name(int cnum,struct stat *st,char *name)
234 strcpy(name,lp_lockdir());
235 standard_sub(cnum,name);
236 trim_string(name,"","/");
237 if (!*name) return(False);
238 name += strlen(name);
240 sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
241 return(True);
244 /*******************************************************************
245 use the fnum to get the share file name
246 ******************************************************************/
247 static BOOL share_name_fnum(int fnum,char *name)
249 struct stat st;
250 if (fstat(Files[fnum].fd,&st) != 0) return(False);
251 return(share_name(Files[fnum].cnum,&st,name));
255 /*******************************************************************
256 get the share mode of a file using the fnum
257 ******************************************************************/
258 int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
260 struct stat sbuf;
261 if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
262 return(get_share_mode(cnum,&sbuf,pid));
265 /*******************************************************************
266 get the share mode of a file using the files name
267 ******************************************************************/
268 int get_share_mode_byname(int cnum,char *fname,int *pid)
270 struct stat sbuf;
271 if (stat(fname,&sbuf) == -1) return(0);
272 return(get_share_mode(cnum,&sbuf,pid));
276 /*******************************************************************
277 get the share mode of a file
278 ********************************************************************/
279 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
281 pstring fname;
282 int fd2;
283 char buf[16];
284 int ret;
285 time_t t;
287 *pid = 0;
289 if (!share_name(cnum,sbuf,fname)) return(0);
291 fd2 = open(fname,O_RDONLY,0);
292 if (fd2 < 0) return(0);
294 if (read(fd2,buf,16) != 16) {
295 close(fd2);
296 unlink(fname);
297 return(0);
299 close(fd2);
301 t = IVAL(buf,0);
302 ret = IVAL(buf,4);
303 *pid = IVAL(buf,8);
305 if (IVAL(buf,12) != LOCKING_VERSION) {
306 if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
307 *pid = 0;
308 return(0);
311 if (*pid && !process_exists(*pid)) {
312 ret=0;
313 *pid = 0;
316 if (! *pid) unlink(fname); /* XXXXX race, race */
318 if (*pid)
319 DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
321 return(ret);
325 /*******************************************************************
326 del the share mode of a file, if we set it last
327 ********************************************************************/
328 void del_share_mode(int fnum)
330 pstring fname;
331 int fd2;
332 char buf[16];
333 time_t t=0;
334 int pid=0;
335 BOOL del = False;
337 if (!share_name_fnum(fnum,fname)) return;
339 fd2 = open(fname,O_RDONLY,0);
340 if (fd2 < 0) return;
341 if (read(fd2,buf,16) != 16)
342 del = True;
343 close(fd2);
345 if (!del) {
346 t = IVAL(buf,0);
347 pid = IVAL(buf,8);
350 if (!del)
351 if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
352 del = True;
354 if (!del && t == Files[fnum].open_time && pid==(int)getpid())
355 del = True;
357 if (del) {
358 if (!unlink(fname))
359 DEBUG(2,("Deleted share file %s\n",fname));
360 else {
361 DEBUG(3,("Pending delete share file %s\n",fname));
362 if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
363 strcpy(share_del_pending,fname);
369 /*******************************************************************
370 set the share mode of a file
371 ********************************************************************/
372 BOOL set_share_mode(int fnum,int mode)
374 pstring fname;
375 int fd2;
376 char buf[16];
377 int pid = (int)getpid();
379 if (!share_name_fnum(fnum,fname)) return(False);
382 int old_umask = umask(0);
383 fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
384 umask(old_umask);
386 if (fd2 < 0) {
387 DEBUG(2,("Failed to create share file %s\n",fname));
388 return(False);
391 SIVAL(buf,0,Files[fnum].open_time);
392 SIVAL(buf,4,mode);
393 SIVAL(buf,8,pid);
394 SIVAL(buf,12,LOCKING_VERSION);
396 if (write(fd2,buf,16) != 16) {
397 close(fd2);
398 unlink(fname);
399 return(False);
402 write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
404 close(fd2);
406 DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
408 return(True);
412 /*******************************************************************
413 cleanup any stale share files
414 ********************************************************************/
415 void clean_share_files(void)
417 char *lockdir = lp_lockdir();
418 void *dir;
419 char *s;
421 if (!*lockdir) return;
423 dir = opendir(lockdir);
424 if (!dir) return;
426 while ((s=readdirname(dir))) {
427 char buf[16];
428 int pid;
429 int fd;
430 pstring lname;
431 int dev,inode;
433 if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
435 strcpy(lname,lp_lockdir());
436 trim_string(lname,NULL,"/");
437 strcat(lname,"/");
438 strcat(lname,s);
440 fd = open(lname,O_RDONLY,0);
441 if (fd < 0) continue;
443 if (read(fd,buf,16) != 16) {
444 close(fd);
445 if (!unlink(lname))
446 printf("Deleted corrupt share file %s\n",s);
447 continue;
449 close(fd);
451 pid = IVAL(buf,8);
453 if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
454 if (!unlink(lname))
455 printf("Deleted stale share file %s\n",s);
459 closedir(dir);