e81e1125e80e93a65e13a3b3a02c854a92aa09fd
[samba.git] / source3 / 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 extern int DEBUGLEVEL;
24 extern connection_struct Connections[];
25 extern files_struct Files[];
26
27 pstring share_del_pending="";
28
29
30 /****************************************************************************
31 routine to do file locking
32 ****************************************************************************/
33 BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
34 {
35 #if HAVE_FCNTL_LOCK
36   struct flock lock;
37   int ret;
38
39 #if 1
40   uint32 mask = 0xC0000000;
41
42   /* make sure the count is reasonable, we might kill the lockd otherwise */
43   count &= ~mask;
44
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);
53
54   /* interpret negative counts as large numbers */
55   if (count < 0)
56     count &= ~mask;
57
58   /* no negative offsets */
59   offset &= ~mask;
60
61   /* count + offset must be in range */
62   while ((offset < 0 || (offset + count < 0)) && mask)
63     {
64       offset &= ~mask;
65       mask = mask >> 1;
66     }
67 #endif
68
69
70   DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
71
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;
77
78   errno = 0;
79
80   ret = fcntl(fd,op,&lock);
81
82   if (errno != 0)
83     DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
84
85   /* a lock query */
86   if (op == F_GETLK)
87     {
88       if ((ret != -1) &&
89           (lock.l_type != F_UNLCK) && 
90           (lock.l_pid != 0) && 
91           (lock.l_pid != getpid()))
92         {
93           DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
94           return(True);
95         }
96
97       /* it must be not locked or locked by me */
98       return(False);
99     }
100
101   /* a lock set or unset */
102   if (ret == -1)
103     {
104       DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
105                offset,count,op,type,strerror(errno)));
106
107       /* perhaps it doesn't support this sort of locking?? */
108       if (errno == EINVAL)
109         {
110           DEBUG(3,("locking not supported? returning True\n"));
111           return(True);
112         }
113
114       return(False);
115     }
116
117   /* everything went OK */
118   DEBUG(5,("Lock call successful\n"));
119
120   return(True);
121 #else
122   return(False);
123 #endif
124 }
125
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)
131 {  
132   int fd = open(name,O_RDWR|O_CREAT,0666);
133   time_t t=0;
134   if (fd < 0) return(-1);
135
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);
141   }
142   return(-1);
143 #else
144   return(fd);
145 #endif
146 }
147
148 /*******************************************************************
149 unlock a file locked by file_lock
150 ********************************************************************/
151 void file_unlock(int fd)
152 {
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);
158 }
159
160
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)
165 {
166   int snum = SNUM(cnum);
167
168   if (count == 0)
169     return(False);
170
171   if (!lp_locking(snum) || !lp_strict_locking(snum))
172     return(False);
173
174   return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
175                     (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
176 }
177
178
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)
183 {
184   BOOL ok = False;
185
186   if (!lp_locking(SNUM(cnum)))
187     return(True);
188
189   if (count == 0) {
190     *eclass = ERRDOS;
191     *ecode = ERRnoaccess;
192     return False;
193   }
194
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));
198
199   if (!ok) {
200     *eclass = ERRDOS;
201     *ecode = ERRlock;
202     return False;
203   }
204   return True; /* Got lock */
205 }
206
207
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)
212 {
213   BOOL ok = False;
214
215   if (!lp_locking(SNUM(cnum)))
216     return(True);
217
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);
220    
221   if (!ok) {
222     *eclass = ERRDOS;
223     *ecode = ERRlock;
224     return False;
225   }
226   return True; /* Did unlock */
227 }
228
229 /*******************************************************************
230   name a share file
231   ******************************************************************/
232 static BOOL share_name(int cnum,struct stat *st,char *name)
233 {
234   strcpy(name,lp_lockdir());
235   standard_sub(cnum,name);
236   trim_string(name,"","/");
237   if (!*name) return(False);
238   name += strlen(name);
239   
240   sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
241   return(True);
242 }
243
244 /*******************************************************************
245   use the fnum to get the share file name
246   ******************************************************************/
247 static BOOL share_name_fnum(int fnum,char *name)
248 {
249   struct stat st;
250   if (fstat(Files[fnum].fd,&st) != 0) return(False);
251   return(share_name(Files[fnum].cnum,&st,name));
252 }
253
254
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)
259 {
260   struct stat sbuf;
261   if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
262   return(get_share_mode(cnum,&sbuf,pid));
263 }
264
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)
269 {
270   struct stat sbuf;
271   if (stat(fname,&sbuf) == -1) return(0);
272   return(get_share_mode(cnum,&sbuf,pid));
273 }  
274
275
276 /*******************************************************************
277 get the share mode of a file
278 ********************************************************************/
279 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
280 {
281   pstring fname;
282   int fd2;
283   char buf[16];
284   int ret;
285   time_t t;
286
287   *pid = 0;
288
289   if (!share_name(cnum,sbuf,fname)) return(0);
290
291   fd2 = open(fname,O_RDONLY,0);
292   if (fd2 < 0) return(0);
293
294   if (read(fd2,buf,16) != 16) {
295     close(fd2);
296     unlink(fname);
297     return(0);
298   }
299   close(fd2);
300
301   t = IVAL(buf,0);
302   ret = IVAL(buf,4);
303   *pid = IVAL(buf,8);
304   
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);
309   }
310
311   if (*pid && !process_exists(*pid)) {
312     ret=0;
313     *pid = 0;
314   }
315
316   if (! *pid) unlink(fname); /* XXXXX race, race */
317
318   if (*pid)
319     DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
320
321   return(ret);
322 }
323
324
325 /*******************************************************************
326 del the share mode of a file, if we set it last
327 ********************************************************************/
328 void del_share_mode(int fnum)
329 {
330   pstring fname;
331   int fd2;
332   char buf[16];
333   time_t t=0;
334   int pid=0;
335   BOOL del = False;
336
337   if (!share_name_fnum(fnum,fname)) return;
338
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);
344
345   if (!del) {
346     t = IVAL(buf,0);
347     pid = IVAL(buf,8);
348   }
349
350   if (!del)
351     if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
352       del = True;
353
354   if (!del && t == Files[fnum].open_time && pid==(int)getpid())
355     del = True;
356
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);
364     }
365   }
366 }
367   
368
369 /*******************************************************************
370 set the share mode of a file
371 ********************************************************************/
372 BOOL set_share_mode(int fnum,int mode)
373 {
374   pstring fname;
375   int fd2;
376   char buf[16];
377   int pid = (int)getpid();
378
379   if (!share_name_fnum(fnum,fname)) return(False);
380
381   {
382     int old_umask = umask(0);
383     fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
384     umask(old_umask);
385   }
386   if (fd2 < 0) {
387     DEBUG(2,("Failed to create share file %s\n",fname));
388     return(False);
389   }
390
391   SIVAL(buf,0,Files[fnum].open_time);
392   SIVAL(buf,4,mode);
393   SIVAL(buf,8,pid);
394   SIVAL(buf,12,LOCKING_VERSION);
395
396   if (write(fd2,buf,16) != 16) {
397     close(fd2);
398     unlink(fname);
399     return(False);
400   }
401
402   write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
403
404   close(fd2);
405
406   DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
407
408   return(True);
409 }
410   
411
412 /*******************************************************************
413 cleanup any stale share files
414 ********************************************************************/
415 void clean_share_files(void)
416 {
417   char *lockdir = lp_lockdir();
418   void *dir;
419   char *s;
420
421   if (!*lockdir) return;
422
423   dir = opendir(lockdir);
424   if (!dir) return;
425
426   while ((s=readdirname(dir))) {
427     char buf[16];
428     int pid;
429     int fd;
430     pstring lname;
431     int dev,inode;
432
433     if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
434
435     strcpy(lname,lp_lockdir());
436     trim_string(lname,NULL,"/");
437     strcat(lname,"/");
438     strcat(lname,s);
439
440     fd = open(lname,O_RDONLY,0);
441     if (fd < 0) continue;
442
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;
448     }
449     close(fd);
450
451     pid = IVAL(buf,8);
452
453     if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
454       if (!unlink(lname))
455         printf("Deleted stale share file %s\n",s);
456     }
457   }
458
459   closedir(dir);
460 }