moved some more locking routines to locking.c, and moved replacement
[samba.git] / source / locking / locking.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Locking functions
5    Copyright (C) Andrew Tridgell 1992-1995
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23 #include "loadparm.h"
24 extern int DEBUGLEVEL;
25 extern connection_struct Connections[];
26 extern files_struct Files[];
27
28 pstring share_del_pending="";
29
30
31 /****************************************************************************
32 routine to do file locking
33 ****************************************************************************/
34 BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
35 {
36 #if HAVE_FCNTL_LOCK
37   struct flock lock;
38   int ret;
39
40 #if 1
41   uint32 mask = 0xC0000000;
42
43   /* make sure the count is reasonable, we might kill the lockd otherwise */
44   count &= ~mask;
45
46   /* the offset is often strange - remove 2 of its bits if either of
47      the top two bits are set. Shift the top ones by two bits. This
48      still allows OLE2 apps to operate, but should stop lockd from
49      dieing */
50   if ((offset & mask) != 0)
51     offset = (offset & ~mask) | ((offset & mask) >> 2);
52 #else
53   unsigned long mask = ((unsigned)1<<31);
54
55   /* interpret negative counts as large numbers */
56   if (count < 0)
57     count &= ~mask;
58
59   /* no negative offsets */
60   offset &= ~mask;
61
62   /* count + offset must be in range */
63   while ((offset < 0 || (offset + count < 0)) && mask)
64     {
65       offset &= ~mask;
66       mask = mask >> 1;
67     }
68 #endif
69
70
71   DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
72
73   lock.l_type = type;
74   lock.l_whence = SEEK_SET;
75   lock.l_start = (int)offset;
76   lock.l_len = (int)count;
77   lock.l_pid = 0;
78
79   errno = 0;
80
81   ret = fcntl(fd,op,&lock);
82
83   if (errno != 0)
84     DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
85
86   /* a lock query */
87   if (op == F_GETLK)
88     {
89       if ((ret != -1) &&
90           (lock.l_type != F_UNLCK) && 
91           (lock.l_pid != 0) && 
92           (lock.l_pid != getpid()))
93         {
94           DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
95           return(True);
96         }
97
98       /* it must be not locked or locked by me */
99       return(False);
100     }
101
102   /* a lock set or unset */
103   if (ret == -1)
104     {
105       DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
106                offset,count,op,type,strerror(errno)));
107
108       /* perhaps it doesn't support this sort of locking?? */
109       if (errno == EINVAL)
110         {
111           DEBUG(3,("locking not supported? returning True\n"));
112           return(True);
113         }
114
115       return(False);
116     }
117
118   /* everything went OK */
119   DEBUG(5,("Lock call successful\n"));
120
121   return(True);
122 #else
123   return(False);
124 #endif
125 }
126
127 /*******************************************************************
128 lock a file - returning a open file descriptor or -1 on failure
129 The timeout is in seconds. 0 means no timeout
130 ********************************************************************/
131 int file_lock(char *name,int timeout)
132 {  
133   int fd = open(name,O_RDWR|O_CREAT,0666);
134   time_t t=0;
135   if (fd < 0) return(-1);
136
137 #if HAVE_FCNTL_LOCK
138   if (timeout) t = time(NULL);
139   while (!timeout || (time(NULL)-t < timeout)) {
140     if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);    
141     msleep(LOCK_RETRY_TIMEOUT);
142   }
143   return(-1);
144 #else
145   return(fd);
146 #endif
147 }
148
149 /*******************************************************************
150 unlock a file locked by file_lock
151 ********************************************************************/
152 void file_unlock(int fd)
153 {
154   if (fd<0) return;
155 #if HAVE_FCNTL_LOCK
156   fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
157 #endif
158   close(fd);
159 }
160
161
162 /****************************************************************************
163   utility function called to see if a file region is locked
164 ****************************************************************************/
165 BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
166 {
167   int snum = SNUM(cnum);
168
169   if (count == 0)
170     return(False);
171
172   if (!lp_locking(snum) || !lp_strict_locking(snum))
173     return(False);
174
175   return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
176                     (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
177 }
178
179
180 /****************************************************************************
181   utility function called by locking requests
182 ****************************************************************************/
183 BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
184 {
185   BOOL ok = False;
186
187   if (!lp_locking(SNUM(cnum)))
188     return(True);
189
190   if (count == 0) {
191     *eclass = ERRDOS;
192     *ecode = ERRnoaccess;
193     return False;
194   }
195
196   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
197     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
198                     (Files[fnum].can_write?F_WRLCK:F_RDLCK));
199
200   if (!ok) {
201     *eclass = ERRDOS;
202     *ecode = ERRlock;
203     return False;
204   }
205   return True; /* Got lock */
206 }
207
208
209 /****************************************************************************
210   utility function called by unlocking requests
211 ****************************************************************************/
212 BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
213 {
214   BOOL ok = False;
215
216   if (!lp_locking(SNUM(cnum)))
217     return(True);
218
219   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
220     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
221    
222   if (!ok) {
223     *eclass = ERRDOS;
224     *ecode = ERRlock;
225     return False;
226   }
227   return True; /* Did unlock */
228 }
229
230 /*******************************************************************
231   name a share file
232   ******************************************************************/
233 static BOOL share_name(int cnum,struct stat *st,char *name)
234 {
235   strcpy(name,lp_lockdir());
236   standard_sub(cnum,name);
237   trim_string(name,"","/");
238   if (!*name) return(False);
239   name += strlen(name);
240   
241   sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
242   return(True);
243 }
244
245 /*******************************************************************
246   use the fnum to get the share file name
247   ******************************************************************/
248 static BOOL share_name_fnum(int fnum,char *name)
249 {
250   struct stat st;
251   if (fstat(Files[fnum].fd,&st) != 0) return(False);
252   return(share_name(Files[fnum].cnum,&st,name));
253 }
254
255
256 /*******************************************************************
257   get the share mode of a file using the fnum
258   ******************************************************************/
259 int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
260 {
261   struct stat sbuf;
262   if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
263   return(get_share_mode(cnum,&sbuf,pid));
264 }
265
266 /*******************************************************************
267   get the share mode of a file using the files name
268   ******************************************************************/
269 int get_share_mode_byname(int cnum,char *fname,int *pid)
270 {
271   struct stat sbuf;
272   if (stat(fname,&sbuf) == -1) return(0);
273   return(get_share_mode(cnum,&sbuf,pid));
274 }  
275
276
277 /*******************************************************************
278 get the share mode of a file
279 ********************************************************************/
280 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
281 {
282   pstring fname;
283   int fd2;
284   char buf[16];
285   int ret;
286   time_t t;
287
288   *pid = 0;
289
290   if (!share_name(cnum,sbuf,fname)) return(0);
291
292   fd2 = open(fname,O_RDONLY,0);
293   if (fd2 < 0) return(0);
294
295   if (read(fd2,buf,16) != 16) {
296     close(fd2);
297     unlink(fname);
298     return(0);
299   }
300   close(fd2);
301
302   t = IVAL(buf,0);
303   ret = IVAL(buf,4);
304   *pid = IVAL(buf,8);
305   
306   if (IVAL(buf,12) != LOCKING_VERSION) {    
307     if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
308     *pid = 0;
309     return(0);
310   }
311
312   if (*pid && !process_exists(*pid)) {
313     ret=0;
314     *pid = 0;
315   }
316
317   if (! *pid) unlink(fname); /* XXXXX race, race */
318
319   if (*pid)
320     DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
321
322   return(ret);
323 }
324
325
326 /*******************************************************************
327 del the share mode of a file, if we set it last
328 ********************************************************************/
329 void del_share_mode(int fnum)
330 {
331   pstring fname;
332   int fd2;
333   char buf[16];
334   time_t t=0;
335   int pid=0;
336   BOOL del = False;
337
338   if (!share_name_fnum(fnum,fname)) return;
339
340   fd2 = open(fname,O_RDONLY,0);
341   if (fd2 < 0) return;
342   if (read(fd2,buf,16) != 16)
343     del = True;
344   close(fd2);
345
346   if (!del) {
347     t = IVAL(buf,0);
348     pid = IVAL(buf,8);
349   }
350
351   if (!del)
352     if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
353       del = True;
354
355   if (!del && t == Files[fnum].open_time && pid==(int)getpid())
356     del = True;
357
358   if (del) {
359     if (!unlink(fname)) 
360       DEBUG(2,("Deleted share file %s\n",fname));
361     else {
362       DEBUG(3,("Pending delete share file %s\n",fname));
363       if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
364       strcpy(share_del_pending,fname);
365     }
366   }
367 }
368   
369
370 /*******************************************************************
371 set the share mode of a file
372 ********************************************************************/
373 BOOL set_share_mode(int fnum,int mode)
374 {
375   pstring fname;
376   int fd2;
377   char buf[16];
378   int pid = (int)getpid();
379
380   if (!share_name_fnum(fnum,fname)) return(False);
381
382   {
383     int old_umask = umask(0);
384     fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
385     umask(old_umask);
386   }
387   if (fd2 < 0) {
388     DEBUG(2,("Failed to create share file %s\n",fname));
389     return(False);
390   }
391
392   SIVAL(buf,0,Files[fnum].open_time);
393   SIVAL(buf,4,mode);
394   SIVAL(buf,8,pid);
395   SIVAL(buf,12,LOCKING_VERSION);
396
397   if (write(fd2,buf,16) != 16) {
398     close(fd2);
399     unlink(fname);
400     return(False);
401   }
402
403   write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
404
405   close(fd2);
406
407   DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
408
409   return(True);
410 }
411   
412
413 /*******************************************************************
414 cleanup any stale share files
415 ********************************************************************/
416 void clean_share_files(void)
417 {
418   char *lockdir = lp_lockdir();
419   void *dir;
420   char *s;
421
422   if (!*lockdir) return;
423
424   dir = opendir(lockdir);
425   if (!dir) return;
426
427   while ((s=readdirname(dir))) {
428     char buf[16];
429     int pid;
430     int fd;
431     pstring lname;
432     int dev,inode;
433
434     if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
435
436     strcpy(lname,lp_lockdir());
437     trim_string(lname,NULL,"/");
438     strcat(lname,"/");
439     strcat(lname,s);
440
441     fd = open(lname,O_RDONLY,0);
442     if (fd < 0) continue;
443
444     if (read(fd,buf,16) != 16) {
445       close(fd);
446       if (!unlink(lname))
447         printf("Deleted corrupt share file %s\n",s);
448       continue;
449     }
450     close(fd);
451
452     pid = IVAL(buf,8);
453
454     if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
455       if (!unlink(lname))
456         printf("Deleted stale share file %s\n",s);
457     }
458   }
459
460   closedir(dir);
461 }