Initial version imported to CVS
[tprouty/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   utility function called to see if a file region is locked
33 ****************************************************************************/
34 BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
35 {
36   int snum = SNUM(cnum);
37
38   if (count == 0)
39     return(False);
40
41   if (!lp_locking(snum) || !lp_strict_locking(snum))
42     return(False);
43
44   return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
45                     (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
46 }
47
48
49 /****************************************************************************
50   utility function called by locking requests
51 ****************************************************************************/
52 BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
53 {
54   BOOL ok = False;
55
56   if (!lp_locking(SNUM(cnum)))
57     return(True);
58
59   if (count == 0) {
60     *eclass = ERRDOS;
61     *ecode = ERRnoaccess;
62     return False;
63   }
64
65   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
66     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
67                     (Files[fnum].can_write?F_WRLCK:F_RDLCK));
68
69   if (!ok) {
70     *eclass = ERRDOS;
71     *ecode = ERRlock;
72     return False;
73   }
74   return True; /* Got lock */
75 }
76
77
78 /****************************************************************************
79   utility function called by unlocking requests
80 ****************************************************************************/
81 BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
82 {
83   BOOL ok = False;
84
85   if (!lp_locking(SNUM(cnum)))
86     return(True);
87
88   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
89     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
90    
91   if (!ok) {
92     *eclass = ERRDOS;
93     *ecode = ERRlock;
94     return False;
95   }
96   return True; /* Did unlock */
97 }
98
99 /*******************************************************************
100   name a share file
101   ******************************************************************/
102 static BOOL share_name(int cnum,struct stat *st,char *name)
103 {
104   strcpy(name,lp_lockdir());
105   standard_sub(cnum,name);
106   trim_string(name,"","/");
107   if (!*name) return(False);
108   name += strlen(name);
109   
110   sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
111   return(True);
112 }
113
114 /*******************************************************************
115   use the fnum to get the share file name
116   ******************************************************************/
117 static BOOL share_name_fnum(int fnum,char *name)
118 {
119   struct stat st;
120   if (fstat(Files[fnum].fd,&st) != 0) return(False);
121   return(share_name(Files[fnum].cnum,&st,name));
122 }
123
124
125 /*******************************************************************
126   get the share mode of a file using the fnum
127   ******************************************************************/
128 int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
129 {
130   struct stat sbuf;
131   if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
132   return(get_share_mode(cnum,&sbuf,pid));
133 }
134
135 /*******************************************************************
136   get the share mode of a file using the files name
137   ******************************************************************/
138 int get_share_mode_byname(int cnum,char *fname,int *pid)
139 {
140   struct stat sbuf;
141   if (stat(fname,&sbuf) == -1) return(0);
142   return(get_share_mode(cnum,&sbuf,pid));
143 }  
144
145
146 /*******************************************************************
147 get the share mode of a file
148 ********************************************************************/
149 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
150 {
151   pstring fname;
152   int fd2;
153   char buf[16];
154   int ret;
155   time_t t;
156
157   *pid = 0;
158
159   if (!share_name(cnum,sbuf,fname)) return(0);
160
161   fd2 = open(fname,O_RDONLY,0);
162   if (fd2 < 0) return(0);
163
164   if (read(fd2,buf,16) != 16) {
165     close(fd2);
166     unlink(fname);
167     return(0);
168   }
169   close(fd2);
170
171   t = IVAL(buf,0);
172   ret = IVAL(buf,4);
173   *pid = IVAL(buf,8);
174   
175   if (IVAL(buf,12) != LOCKING_VERSION) {    
176     if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
177     *pid = 0;
178     return(0);
179   }
180
181   if (*pid && !process_exists(*pid)) {
182     ret=0;
183     *pid = 0;
184   }
185
186   if (! *pid) unlink(fname); /* XXXXX race, race */
187
188   if (*pid)
189     DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
190
191   return(ret);
192 }
193
194
195 /*******************************************************************
196 del the share mode of a file, if we set it last
197 ********************************************************************/
198 void del_share_mode(int fnum)
199 {
200   pstring fname;
201   int fd2;
202   char buf[16];
203   time_t t=0;
204   int pid=0;
205   BOOL del = False;
206
207   if (!share_name_fnum(fnum,fname)) return;
208
209   fd2 = open(fname,O_RDONLY,0);
210   if (fd2 < 0) return;
211   if (read(fd2,buf,16) != 16)
212     del = True;
213   close(fd2);
214
215   if (!del) {
216     t = IVAL(buf,0);
217     pid = IVAL(buf,8);
218   }
219
220   if (!del)
221     if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
222       del = True;
223
224   if (!del && t == Files[fnum].open_time && pid==(int)getpid())
225     del = True;
226
227   if (del) {
228     if (!unlink(fname)) 
229       DEBUG(2,("Deleted share file %s\n",fname));
230     else {
231       DEBUG(3,("Pending delete share file %s\n",fname));
232       if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
233       strcpy(share_del_pending,fname);
234     }
235   }
236 }
237   
238
239 /*******************************************************************
240 set the share mode of a file
241 ********************************************************************/
242 BOOL set_share_mode(int fnum,int mode)
243 {
244   pstring fname;
245   int fd2;
246   char buf[16];
247   int pid = (int)getpid();
248
249   if (!share_name_fnum(fnum,fname)) return(False);
250
251   {
252     int old_umask = umask(0);
253     fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
254     umask(old_umask);
255   }
256   if (fd2 < 0) {
257     DEBUG(2,("Failed to create share file %s\n",fname));
258     return(False);
259   }
260
261   SIVAL(buf,0,Files[fnum].open_time);
262   SIVAL(buf,4,mode);
263   SIVAL(buf,8,pid);
264   SIVAL(buf,12,LOCKING_VERSION);
265
266   if (write(fd2,buf,16) != 16) {
267     close(fd2);
268     unlink(fname);
269     return(False);
270   }
271
272   write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
273
274   close(fd2);
275
276   DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
277
278   return(True);
279 }
280   
281
282 /*******************************************************************
283 cleanup any stale share files
284 ********************************************************************/
285 void clean_share_files(void)
286 {
287   char *lockdir = lp_lockdir();
288   void *dir;
289   char *s;
290
291   if (!*lockdir) return;
292
293   dir = opendir(lockdir);
294   if (!dir) return;
295
296   while ((s=readdirname(dir))) {
297     char buf[16];
298     int pid;
299     int fd;
300     pstring lname;
301     int dev,inode;
302
303     if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
304
305     strcpy(lname,lp_lockdir());
306     trim_string(lname,NULL,"/");
307     strcat(lname,"/");
308     strcat(lname,s);
309
310     fd = open(lname,O_RDONLY,0);
311     if (fd < 0) continue;
312
313     if (read(fd,buf,16) != 16) {
314       close(fd);
315       if (!unlink(lname))
316         printf("Deleted corrupt share file %s\n",s);
317       continue;
318     }
319     close(fd);
320
321     pid = IVAL(buf,8);
322
323     if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
324       if (!unlink(lname))
325         printf("Deleted stale share file %s\n",s);
326     }
327   }
328
329   closedir(dir);
330 }