Moved fcntl locking code into util.c to allow it to be
[kai/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-1996
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    Revision History:
22
23    12 aug 96: Erik.Devriendt@te6.siemens.be
24    added support for shared memory implementation of share mode locking
25 */
26
27 #include "includes.h"
28 extern int DEBUGLEVEL;
29 extern connection_struct Connections[];
30 extern files_struct Files[];
31
32 pstring share_del_pending="";
33
34
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)
39 {
40   int snum = SNUM(cnum);
41
42   if (count == 0)
43     return(False);
44
45   if (!lp_locking(snum) || !lp_strict_locking(snum))
46     return(False);
47
48   return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
49                     (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
50 }
51
52
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)
57 {
58   BOOL ok = False;
59
60   if (!lp_locking(SNUM(cnum)))
61     return(True);
62
63   if (count == 0) {
64     *eclass = ERRDOS;
65     *ecode = ERRnoaccess;
66     return False;
67   }
68
69   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
70     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
71                     (Files[fnum].can_write?F_WRLCK:F_RDLCK));
72
73   if (!ok) {
74     *eclass = ERRDOS;
75     *ecode = ERRlock;
76     return False;
77   }
78   return True; /* Got lock */
79 }
80
81
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)
86 {
87   BOOL ok = False;
88
89   if (!lp_locking(SNUM(cnum)))
90     return(True);
91
92   if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
93     ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
94    
95   if (!ok) {
96     *eclass = ERRDOS;
97     *ecode = ERRlock;
98     return False;
99   }
100   return True; /* Did unlock */
101 }
102
103 #if FAST_SHARE_MODES
104 /*******************************************************************
105   initialize the shared memory for share_mode management 
106   ******************************************************************/
107 BOOL start_share_mode_mgmt(void)
108 {
109    pstring shmem_file_name;
110    
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 shm_open(shmem_file_name, SHMEM_SIZE);
118 }
119
120
121 /*******************************************************************
122   deinitialize the shared memory for share_mode management 
123   ******************************************************************/
124 BOOL stop_share_mode_mgmt(void)
125 {
126    return shm_close();
127 }
128
129 #else
130
131 /* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
132
133 /*******************************************************************
134   name a share file
135   ******************************************************************/
136 static BOOL share_name(int cnum,struct stat *st,char *name)
137 {
138   strcpy(name,lp_lockdir());
139   standard_sub(cnum,name);
140   trim_string(name,"","/");
141   if (!*name) return(False);
142   name += strlen(name);
143   
144   sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
145   return(True);
146 }
147
148 /*******************************************************************
149   use the fnum to get the share file name
150   ******************************************************************/
151 static BOOL share_name_fnum(int fnum,char *name)
152 {
153   struct stat st;
154   if (fstat(Files[fnum].fd,&st) != 0) return(False);
155   return(share_name(Files[fnum].cnum,&st,name));
156 }
157
158 #endif
159
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)
164 {
165   struct stat sbuf;
166   if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
167   return(get_share_mode(cnum,&sbuf,pid));
168 }
169
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)
174 {
175   struct stat sbuf;
176   if (stat(fname,&sbuf) == -1) return(0);
177   return(get_share_mode(cnum,&sbuf,pid));
178 }  
179
180
181 /*******************************************************************
182 get the share mode of a file
183 ********************************************************************/
184 int get_share_mode(int cnum,struct stat *sbuf,int *pid)
185 {
186 #if FAST_SHARE_MODES
187   share_mode_record *scanner_p;
188   share_mode_record *prev_p;
189   int ret;
190   BOOL found = False;
191
192   *pid = 0;
193
194   if(!shm_lock()) return (0);
195
196   scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
197   prev_p = scanner_p;
198   while(scanner_p)
199   {
200      if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) )
201      {
202         found = True;
203         break;
204      }
205      else
206      {
207         prev_p = scanner_p ;
208         scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
209      }
210   }
211   
212   if(!found)
213   {
214      shm_unlock();
215      return (0);
216   }
217   
218   if(scanner_p->locking_version != LOCKING_VERSION)
219   {
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         shm_set_userdef_off(scanner_p->next_offset);
223      else
224         prev_p->next_offset = scanner_p->next_offset;
225      shm_free(shm_addr2offset(scanner_p));
226      *pid = 0;
227         
228      shm_unlock();
229      return (0);
230   }
231   
232   *pid = scanner_p->pid;
233   ret = scanner_p->share_mode;
234
235   if (*pid && !process_exists(*pid))
236   {
237     ret = 0;
238     *pid = 0;
239   }
240   
241   if (! *pid)
242   {
243      if(prev_p == scanner_p)
244         shm_set_userdef_off(scanner_p->next_offset);
245      else
246         prev_p->next_offset = scanner_p->next_offset;
247      shm_free(shm_addr2offset(scanner_p));
248   }
249   
250   if (*pid)
251     DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid));
252
253   if(!shm_unlock()) return (0);
254   
255   return(ret);
256   
257 #else
258   pstring fname;
259   int fd2;
260   char buf[16];
261   int ret;
262   time_t t;
263
264   *pid = 0;
265
266   if (!share_name(cnum,sbuf,fname)) return(0);
267
268   fd2 = open(fname,O_RDONLY,0);
269   if (fd2 < 0) return(0);
270
271   if (read(fd2,buf,16) != 16) {
272     close(fd2);
273     unlink(fname);
274     return(0);
275   }
276   close(fd2);
277
278   t = IVAL(buf,0);
279   ret = IVAL(buf,4);
280   *pid = IVAL(buf,8);
281   
282   if (IVAL(buf,12) != LOCKING_VERSION) {    
283     if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
284     *pid = 0;
285     return(0);
286   }
287
288   if (*pid && !process_exists(*pid)) {
289     ret=0;
290     *pid = 0;
291   }
292
293   if (! *pid) unlink(fname); /* XXXXX race, race */
294
295   if (*pid)
296     DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
297
298   return(ret);
299 #endif
300 }
301
302
303 /*******************************************************************
304 del the share mode of a file, if we set it last
305 ********************************************************************/
306 void del_share_mode(int fnum)
307 {
308 #if FAST_SHARE_MODES
309   struct stat st;
310   time_t t=0;
311   int pid=0;
312   BOOL del = False;
313   share_mode_record *scanner_p;
314   share_mode_record *prev_p;
315   BOOL found = False;
316
317   
318   
319   if (fstat(Files[fnum].fd,&st) != 0) return;
320   
321   if (!shm_lock()) return;
322   
323   scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
324   prev_p = scanner_p;
325   while(scanner_p)
326   {
327      if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
328      {
329         found = True;
330         break;
331      }
332      else
333      {
334         prev_p = scanner_p ;
335         scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
336      }
337   }
338     
339   if(!found)
340   {
341      shm_unlock();
342      return;
343   }
344   
345   t = scanner_p->time;
346   pid = scanner_p->pid;
347   
348   if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
349     del = True;
350
351   if (!del && t == Files[fnum].open_time && pid==(int)getpid())
352     del = True;
353
354   if (del)
355   {
356      DEBUG(2,("Deleting share mode record\n"));
357      if(prev_p == scanner_p)
358         shm_set_userdef_off(scanner_p->next_offset);
359      else
360         prev_p->next_offset = scanner_p->next_offset;
361      shm_free(shm_addr2offset(scanner_p));
362         
363   }
364
365   shm_unlock();
366   return;
367
368 #else
369   pstring fname;
370   int fd2;
371   char buf[16];
372   time_t t=0;
373   int pid=0;
374   BOOL del = False;
375
376   if (!share_name_fnum(fnum,fname)) return;
377
378   fd2 = open(fname,O_RDONLY,0);
379   if (fd2 < 0) return;
380   if (read(fd2,buf,16) != 16)
381     del = True;
382   close(fd2);
383
384   if (!del) {
385     t = IVAL(buf,0);
386     pid = IVAL(buf,8);
387   }
388
389   if (!del)
390     if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
391       del = True;
392
393   if (!del && t == Files[fnum].open_time && pid==(int)getpid())
394     del = True;
395
396   if (del) {
397     if (!unlink(fname)) 
398       DEBUG(2,("Deleted share file %s\n",fname));
399     else {
400       DEBUG(3,("Pending delete share file %s\n",fname));
401       if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
402       strcpy(share_del_pending,fname);
403     }
404   }
405 #endif
406 }
407   
408
409 /*******************************************************************
410 set the share mode of a file
411 ********************************************************************/
412 BOOL set_share_mode(int fnum,int mode)
413 {
414 #if FAST_SHARE_MODES
415   int pid = (int)getpid();
416   struct stat st;
417   shm_offset_t new_off;
418   share_mode_record *new_p;
419   
420   
421   if (fstat(Files[fnum].fd,&st) != 0) return(False);
422   
423   if (!shm_lock()) return (False);
424   new_off = shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
425   if (new_off == NULL_OFFSET) return (False);
426   new_p = (share_mode_record *)shm_offset2addr(new_off);
427   new_p->locking_version = LOCKING_VERSION;
428   new_p->share_mode = mode;
429   new_p->time = Files[fnum].open_time;
430   new_p->pid = pid;
431   new_p->st_dev = st.st_dev;
432   new_p->st_ino = st.st_ino;
433   strcpy(new_p->file_name,Files[fnum].name);
434   new_p->next_offset = shm_get_userdef_off();
435   shm_set_userdef_off(new_off);
436
437
438   DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
439
440   if (!shm_unlock()) return (False);
441   return(True);
442
443 #else
444   pstring fname;
445   int fd2;
446   char buf[16];
447   int pid = (int)getpid();
448
449   if (!share_name_fnum(fnum,fname)) return(False);
450
451   {
452     int old_umask = umask(0);
453     fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
454     umask(old_umask);
455   }
456   if (fd2 < 0) {
457     DEBUG(2,("Failed to create share file %s\n",fname));
458     return(False);
459   }
460
461   SIVAL(buf,0,Files[fnum].open_time);
462   SIVAL(buf,4,mode);
463   SIVAL(buf,8,pid);
464   SIVAL(buf,12,LOCKING_VERSION);
465
466   if (write(fd2,buf,16) != 16) {
467     close(fd2);
468     unlink(fname);
469     return(False);
470   }
471
472   write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
473
474   close(fd2);
475
476   DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
477
478   return(True);
479 #endif
480 }
481   
482
483 /*******************************************************************
484 cleanup any stale share files
485 ********************************************************************/
486 void clean_share_modes(void)
487 {
488 #ifdef USE_SHMEM
489   share_mode_record *scanner_p;
490   share_mode_record *prev_p;
491   int pid;
492   
493   if (!shm_lock()) return;
494   
495   scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
496   prev_p = scanner_p;
497   while(scanner_p)
498   {
499      pid = scanner_p->pid;
500      
501      if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
502      {
503         DEBUG(2,("Deleting stale share mode record"));
504         if(prev_p == scanner_p)
505         {
506            shm_set_userdef_off(scanner_p->next_offset);
507            shm_free(shm_addr2offset(scanner_p));
508            scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
509            prev_p = scanner_p;
510         }
511         else
512         {
513            prev_p->next_offset = scanner_p->next_offset;
514            shm_free(shm_addr2offset(scanner_p));
515            scanner_p = (share_mode_record *)shm_offset2addr(prev_p->next_offset);
516         }
517         
518      }
519      else
520      {
521         prev_p = scanner_p ;
522         scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
523      }
524   }
525     
526
527   shm_unlock();
528   return;
529   
530 #else
531   char *lockdir = lp_lockdir();
532   void *dir;
533   char *s;
534
535   if (!*lockdir) return;
536
537   dir = opendir(lockdir);
538   if (!dir) return;
539
540   while ((s=readdirname(dir))) {
541     char buf[16];
542     int pid;
543     int fd;
544     pstring lname;
545     int dev,inode;
546
547     if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
548
549     strcpy(lname,lp_lockdir());
550     trim_string(lname,NULL,"/");
551     strcat(lname,"/");
552     strcat(lname,s);
553
554     fd = open(lname,O_RDONLY,0);
555     if (fd < 0) continue;
556
557     if (read(fd,buf,16) != 16) {
558       close(fd);
559       if (!unlink(lname))
560         printf("Deleted corrupt share file %s\n",s);
561       continue;
562     }
563     close(fd);
564
565     pid = IVAL(buf,8);
566
567     if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
568       if (!unlink(lname))
569         printf("Deleted stale share file %s\n",s);
570     }
571   }
572
573   closedir(dir);
574 #endif
575 }