'The mother of all checkins' :-). Jeremy Allison (jallison@whistle.com)
[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-1997
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_ptr->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_ptr->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_ptr->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 smb_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 smb_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_ptr->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_ptr->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(!smb_shm_lock()) return (0);
195
196   scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_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 *)smb_shm_offset2addr(scanner_p->next_offset);
209      }
210   }
211   
212   if(!found)
213   {
214      smb_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         smb_shm_set_userdef_off(scanner_p->next_offset);
223      else
224         prev_p->next_offset = scanner_p->next_offset;
225      smb_shm_free(smb_shm_addr2offset(scanner_p));
226      *pid = 0;
227         
228      smb_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         smb_shm_set_userdef_off(scanner_p->next_offset);
245      else
246         prev_p->next_offset = scanner_p->next_offset;
247      smb_shm_free(smb_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(!smb_shm_unlock()) return (0);
254   
255   return(ret);
256   
257 #else
258   pstring fname;
259   int fd2;
260   char buf[20];
261   int ret;
262   struct timeval 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,20) != 20) {
272     DEBUG(2,("Failed to read share file %s\n",fname));
273     close(fd2);
274     unlink(fname);
275     return(0);
276   }
277   close(fd2);
278
279   t.tv_sec = IVAL(buf,4);
280   t.tv_usec = IVAL(buf,8);
281   ret = IVAL(buf,12);
282   *pid = IVAL(buf,16);
283   
284   if (IVAL(buf,0) != LOCKING_VERSION) {    
285     if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
286     *pid = 0;
287     return(0);
288   }
289
290   if (*pid && !process_exists(*pid)) {
291     ret=0;
292     *pid = 0;
293   }
294
295   if (! *pid) unlink(fname); /* XXXXX race, race */
296
297   if (*pid)
298     DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
299
300   return(ret);
301 #endif
302 }
303
304
305 /*******************************************************************
306 del the share mode of a file, if we set it last
307 ********************************************************************/
308 void del_share_mode(int fnum)
309 {
310 #if FAST_SHARE_MODES
311   struct stat st;
312   struct timeval t;
313   int pid=0;
314   BOOL del = False;
315   share_mode_record *scanner_p;
316   share_mode_record *prev_p;
317   BOOL found = False;
318
319   t.tv_sec = t.tv_usec = 0;
320   
321   if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return;
322   
323   if (!smb_shm_lock()) return;
324   
325   scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
326   prev_p = scanner_p;
327   while(scanner_p)
328   {
329      if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
330      {
331         found = True;
332         break;
333      }
334      else
335      {
336         prev_p = scanner_p ;
337         scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
338      }
339   }
340     
341   if(!found)
342   {
343      smb_shm_unlock();
344      return;
345   }
346   
347   t.tv_sec = scanner_p->time.tv_sec;
348   t.tv_usec = scanner_p->time.tv_usec;
349   pid = scanner_p->pid;
350   
351   if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
352     del = True;
353
354   if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0)
355       && pid==(int)getpid())
356     del = True;
357
358   if (del)
359   {
360      DEBUG(2,("Deleting share mode record\n"));
361      if(prev_p == scanner_p)
362         smb_shm_set_userdef_off(scanner_p->next_offset);
363      else
364         prev_p->next_offset = scanner_p->next_offset;
365      smb_shm_free(smb_shm_addr2offset(scanner_p));
366         
367   }
368
369   smb_shm_unlock();
370   return;
371
372 #else
373   pstring fname;
374   int fd2;
375   char buf[20];
376   struct timeval t;
377   int pid=0;
378   BOOL del = False;
379
380   t.tv_sec = t.tv_usec = 0;
381   if (!share_name_fnum(fnum,fname)) return;
382
383   fd2 = open(fname,O_RDONLY,0);
384   if (fd2 < 0) return;
385   if (read(fd2,buf,20) != 20)
386     del = True;
387   close(fd2);
388
389   if (!del) {
390     t.tv_sec = IVAL(buf,4);
391     t.tv_usec = IVAL(buf,8);
392     pid = IVAL(buf,16);
393   }
394
395   if (!del)
396     if (IVAL(buf,0) != LOCKING_VERSION || !pid || !process_exists(pid))
397       del = True;
398
399   if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0) && (pid==(int)getpid()))
400     del = True;
401
402   if (del) {
403     if (!unlink(fname)) 
404       DEBUG(2,("Deleted share file %s\n",fname));
405     else {
406       DEBUG(3,("Pending delete share file %s\n",fname));
407       if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
408       strcpy(share_del_pending,fname);
409     }
410   }
411 #endif
412 }
413   
414
415 /*******************************************************************
416 set the share mode of a file
417 ********************************************************************/
418 BOOL set_share_mode(int fnum,int mode)
419 {
420 #if FAST_SHARE_MODES
421   int pid = (int)getpid();
422   struct stat st;
423   smb_shm_offset_t new_off;
424   share_mode_record *new_p;
425   
426   
427   if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
428   
429   if (!smb_shm_lock()) return (False);
430   new_off = smb_shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
431   if (new_off == NULL_OFFSET) return (False);
432   new_p = (share_mode_record *)smb_shm_offset2addr(new_off);
433   new_p->locking_version = LOCKING_VERSION;
434   new_p->share_mode = mode;
435   new_p->time.tv_sec = Files[fnum].open_time.tv_sec;
436   new_p->time.tv_usec = Files[fnum].open_time.tv_usec;
437   new_p->pid = pid;
438   new_p->st_dev = st.st_dev;
439   new_p->st_ino = st.st_ino;
440   strcpy(new_p->file_name,Files[fnum].name);
441   new_p->next_offset = smb_shm_get_userdef_off();
442   smb_shm_set_userdef_off(new_off);
443
444
445   DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
446
447   if (!smb_shm_unlock()) return (False);
448   return(True);
449
450 #else
451   pstring fname;
452   int fd2;
453   char buf[20];
454   int pid = (int)getpid();
455
456   if (!share_name_fnum(fnum,fname)) return(False);
457
458   {
459     int old_umask = umask(0);
460     fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
461     umask(old_umask);
462   }
463   if (fd2 < 0) {
464     DEBUG(2,("Failed to create share file %s\n",fname));
465     return(False);
466   }
467
468   SIVAL(buf,0,LOCKING_VERSION);
469   SIVAL(buf,4,Files[fnum].open_time.tv_sec);
470   SIVAL(buf,8,Files[fnum].open_time.tv_usec);
471   SIVAL(buf,12,mode);
472   SIVAL(buf,16,pid);
473
474   if (write(fd2,buf,20) != 20) {
475     DEBUG(2,("Failed to write share file %s\n",fname));
476     close(fd2);
477     unlink(fname);
478     return(False);
479   }
480
481   write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
482
483   close(fd2);
484
485   DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
486
487   return(True);
488 #endif
489 }
490   
491
492 /*******************************************************************
493 cleanup any stale share files
494 ********************************************************************/
495 void clean_share_modes(void)
496 {
497 #ifdef USE_SHMEM
498   share_mode_record *scanner_p;
499   share_mode_record *prev_p;
500   int pid;
501   
502   if (!smb_shm_lock()) return;
503   
504   scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
505   prev_p = scanner_p;
506   while(scanner_p)
507   {
508      pid = scanner_p->pid;
509      
510      if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
511      {
512         DEBUG(2,("Deleting stale share mode record"));
513         if(prev_p == scanner_p)
514         {
515            smb_shm_set_userdef_off(scanner_p->next_offset);
516            smb_shm_free(smb_shm_addr2offset(scanner_p));
517            scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
518            prev_p = scanner_p;
519         }
520         else
521         {
522            prev_p->next_offset = scanner_p->next_offset;
523            smb_shm_free(smb_shm_addr2offset(scanner_p));
524            scanner_p = (share_mode_record *)smb_shm_offset2addr(prev_p->next_offset);
525         }
526         
527      }
528      else
529      {
530         prev_p = scanner_p ;
531         scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
532      }
533   }
534     
535
536   smb_shm_unlock();
537   return;
538   
539 #else
540   char *lockdir = lp_lockdir();
541   void *dir;
542   char *s;
543
544   if (!*lockdir) return;
545
546   dir = opendir(lockdir);
547   if (!dir) return;
548
549   while ((s=readdirname(dir))) {
550     char buf[20];
551     int pid;
552     int fd;
553     pstring lname;
554     int dev,inode;
555
556     if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
557
558     strcpy(lname,lp_lockdir());
559     trim_string(lname,NULL,"/");
560     strcat(lname,"/");
561     strcat(lname,s);
562
563     fd = open(lname,O_RDONLY,0);
564     if (fd < 0) continue;
565
566     if (read(fd,buf,20) != 20) {
567       close(fd);
568       if (!unlink(lname))
569         printf("Deleted corrupt share file %s\n",s);
570       continue;
571     }
572     close(fd);
573
574     pid = IVAL(buf,16);
575
576     if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) {
577       if (!unlink(lname))
578         printf("Deleted stale share file %s\n",s);
579     }
580   }
581
582   closedir(dir);
583 #endif
584 }