Syncing up current oplock work in progress. #ifdef'ed out
[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    May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27    locking to deal with multiple share modes per open file.
28 */
29
30 #include "includes.h"
31 extern int DEBUGLEVEL;
32 extern connection_struct Connections[];
33 extern files_struct Files[];
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 #ifdef 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   pstrcpy(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, lp_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 /*******************************************************************
130   lock a hash bucket entry in shared memory for share_mode management 
131   ******************************************************************/
132 BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
133 {
134   return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
135 }
136
137 /*******************************************************************
138   unlock a hash bucket entry in shared memory for share_mode management 
139   ******************************************************************/
140 BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
141 {
142   return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
143 }
144
145 /*******************************************************************
146 get all share mode entries in shared memory for a dev/inode pair.
147 ********************************************************************/
148 int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
149                     min_share_mode_entry **old_shares)
150 {
151   smb_shm_offset_t *mode_array;
152   unsigned int hash_entry = HASH_ENTRY(dev, inode); 
153   share_mode_record *file_scanner_p;
154   share_mode_record *file_prev_p;
155   share_mode_entry *entry_scanner_p;
156   share_mode_entry *entry_prev_p;
157   int num_entries;
158   int num_entries_copied;
159   BOOL found = False;
160   min_share_mode_entry *share_array = (min_share_mode_entry *)0;
161
162   *old_shares = 0;
163
164   if(hash_entry > lp_shmem_hash_size() )
165   {
166     DEBUG(0, 
167       ("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
168 (max = %d)\n",
169       hash_entry, lp_shmem_hash_size() ));
170     return 0;
171   }
172
173   mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
174   
175   if(mode_array[hash_entry] == NULL_OFFSET)
176   {
177     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
178     return 0;
179   }
180
181   file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
182   file_prev_p = file_scanner_p;
183   while(file_scanner_p)
184   {
185     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
186     {
187       found = True;
188       break;
189     }
190     else
191     {
192       file_prev_p = file_scanner_p ;
193       file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
194                                     file_scanner_p->next_offset);
195     }
196   }
197   
198   if(!found)
199   {
200     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
201 file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
202     return (0);
203   }
204   
205   if(file_scanner_p->locking_version != LOCKING_VERSION)
206   {
207     DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
208 record due to old locking version %d for file dev = %d, inode = %d in hash \
209 bucket %d",file_scanner_p->locking_version, dev, inode, hash_entry));
210     if(file_prev_p == file_scanner_p)
211       mode_array[hash_entry] = file_scanner_p->next_offset;
212     else
213       file_prev_p->next_offset = file_scanner_p->next_offset;
214     smb_shm_free(smb_shm_addr2offset(file_scanner_p));
215     return (0);
216   }
217
218   /* Allocate the old_shares array */
219   num_entries = file_scanner_p->num_share_mode_entries;
220   if(num_entries)
221   {
222     *old_shares = share_array = (min_share_mode_entry *)
223                  malloc(num_entries * sizeof(min_share_mode_entry));
224     if(*old_shares == 0)
225     {
226       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
227       return 0;
228     }
229   }
230
231   num_entries_copied = 0;
232   
233   entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
234                                            file_scanner_p->share_mode_entries);
235   entry_prev_p = entry_scanner_p;
236   while(entry_scanner_p)
237   {
238     int pid = entry_scanner_p->pid;
239
240     if (pid && !process_exists(pid))
241     {
242       /* Delete this share mode entry */
243       share_mode_entry *delete_entry_p = entry_scanner_p;
244
245       if(entry_prev_p == entry_scanner_p)
246       {
247         /* We are at start of list */
248         file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
249         entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
250                                            file_scanner_p->share_mode_entries);
251         entry_prev_p = entry_scanner_p;
252       }
253       else
254       {
255         entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
256         entry_scanner_p = (share_mode_entry*)
257                            smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
258       }
259       /* Decrement the number of share mode entries on this share mode record */
260       file_scanner_p->num_share_mode_entries -= 1;
261
262       /* PARANOIA TEST */
263       if(file_scanner_p->num_share_mode_entries < 0)
264       {
265         DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
266 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
267              dev, inode, hash_entry));
268         return 0;
269       }
270
271       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
272 it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
273 bucket (number of entries now = %d)\n", 
274             pid, entry_scanner_p->share_mode, dev, inode, hash_entry,
275             file_scanner_p->num_share_mode_entries));
276
277       smb_shm_free(smb_shm_addr2offset(delete_entry_p));
278     } 
279     else
280     {
281        /* This is a valid share mode entry and the process that
282            created it still exists. Copy it into the output array.
283        */
284        share_array[num_entries_copied].pid = entry_scanner_p->pid;
285        share_array[num_entries_copied].share_mode = entry_scanner_p->share_mode;
286 #ifdef USE_OPLOCKS
287        share_array[num_entries_copied].op_port = entry_scanner_p->op_port;
288        share_array[num_entries_copied].op_type = entry_scanner_p->op_type;
289 #endif /* USE_OPLOCKS */
290        memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->time,
291               sizeof(struct timeval));
292        num_entries_copied++;
293        DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
294 record mode 0x%X pid=%d\n", entry_scanner_p->share_mode, entry_scanner_p->pid));
295        entry_prev_p = entry_scanner_p;
296        entry_scanner_p = (share_mode_entry *)
297                            smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
298     }
299   }
300   
301   /* If no valid share mode entries were found then this record shouldn't exist ! */
302   if(num_entries_copied == 0)
303   {
304     DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
305 hash bucket %d has a share mode record but no entries - deleting\n", 
306                  dev, inode, hash_entry));
307     if(*old_shares)
308       free((char *)*old_shares);
309     *old_shares = 0;
310
311     if(file_prev_p == file_scanner_p)
312       mode_array[hash_entry] = file_scanner_p->next_offset;
313     else
314       file_prev_p->next_offset = file_scanner_p->next_offset;
315     smb_shm_free(smb_shm_addr2offset(file_scanner_p));
316   }
317
318   DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
319 hash bucket %d returning %d entries\n", dev, inode, hash_entry,
320                          num_entries_copied));
321
322   return(num_entries_copied);
323 }  
324
325 /*******************************************************************
326 del the share mode of a file.
327 ********************************************************************/
328 void del_share_mode(share_lock_token token, int fnum)
329 {
330   uint32 dev, inode;
331   smb_shm_offset_t *mode_array;
332   unsigned int hash_entry;
333   share_mode_record *file_scanner_p;
334   share_mode_record *file_prev_p;
335   share_mode_entry *entry_scanner_p;
336   share_mode_entry *entry_prev_p;
337   BOOL found = False;
338   int pid = getpid();
339
340   dev = Files[fnum].fd_ptr->dev;
341   inode = Files[fnum].fd_ptr->inode;
342
343   hash_entry = HASH_ENTRY(dev, inode);
344
345   if(hash_entry > lp_shmem_hash_size() )
346   {
347     DEBUG(0,
348       ("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
349 (max = %d)\n",
350       hash_entry, lp_shmem_hash_size() ));
351     return;
352   }
353
354   mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
355  
356   if(mode_array[hash_entry] == NULL_OFFSET)
357   {  
358     DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n", 
359                   hash_entry));
360     return;
361   }  
362   
363   file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
364   file_prev_p = file_scanner_p;
365
366   while(file_scanner_p)
367   {
368     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
369     {
370       found = True;
371       break;
372     }
373     else
374     {
375       file_prev_p = file_scanner_p ;
376       file_scanner_p = (share_mode_record *)
377                         smb_shm_offset2addr(file_scanner_p->next_offset);
378     }
379   }
380     
381   if(!found)
382   {
383      DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
384 inode %d in hash bucket %d\n", dev, inode, hash_entry));
385      return;
386   }
387   
388   if(file_scanner_p->locking_version != LOCKING_VERSION)
389   {
390     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
391 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
392        file_scanner_p->locking_version, dev, inode, hash_entry ));
393     if(file_prev_p == file_scanner_p)
394       mode_array[hash_entry] = file_scanner_p->next_offset;
395     else
396       file_prev_p->next_offset = file_scanner_p->next_offset;
397     smb_shm_free(smb_shm_addr2offset(file_scanner_p));
398     return;
399   }
400
401   found = False;
402   entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
403                                          file_scanner_p->share_mode_entries);
404   entry_prev_p = entry_scanner_p;
405   while(entry_scanner_p)
406   {
407     if( (pid == entry_scanner_p->pid) && 
408           (memcmp(&entry_scanner_p->time, 
409                  &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
410     {
411       found = True;
412       break;
413     }
414     else
415     {
416       entry_prev_p = entry_scanner_p;
417       entry_scanner_p = (share_mode_entry *)
418                           smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
419     }
420   } 
421
422   if (found)
423   {
424     /* Decrement the number of entries in the record. */
425     file_scanner_p->num_share_mode_entries -= 1;
426
427     DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
428 Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
429               dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
430     if(entry_prev_p == entry_scanner_p)
431       /* We are at start of list */
432       file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
433     else
434       entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
435     smb_shm_free(smb_shm_addr2offset(entry_scanner_p));
436
437     /* PARANOIA TEST */
438     if(file_scanner_p->num_share_mode_entries < 0)
439     {
440       DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
441 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
442            dev, inode, hash_entry));
443       return;
444     }
445
446     /* If we deleted the last share mode entry then remove the share mode record. */
447     if(file_scanner_p->num_share_mode_entries == 0)
448     {
449       DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
450 record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
451       if(file_prev_p == file_scanner_p)
452         mode_array[hash_entry] = file_scanner_p->next_offset;
453       else
454         file_prev_p->next_offset = file_scanner_p->next_offset;
455       smb_shm_free(smb_shm_addr2offset(file_scanner_p));
456     }
457   }
458   else
459   {
460     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
461 dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
462   }
463 }
464
465 /*******************************************************************
466 set the share mode of a file. Return False on fail, True on success.
467 ********************************************************************/
468 BOOL set_share_mode(share_lock_token token, int fnum, uint16 port, uint16 op_type)
469 {
470   files_struct *fs_p = &Files[fnum];
471   int32 dev, inode;
472   smb_shm_offset_t *mode_array;
473   unsigned int hash_entry;
474   share_mode_record *file_scanner_p;
475   share_mode_record *file_prev_p;
476   share_mode_entry *new_entry_p;
477   smb_shm_offset_t new_entry_offset;
478   BOOL found = False;
479
480   dev = fs_p->fd_ptr->dev;
481   inode = fs_p->fd_ptr->inode;
482
483   hash_entry = HASH_ENTRY(dev, inode);
484   if(hash_entry > lp_shmem_hash_size() )
485   {
486     DEBUG(0,
487       ("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
488 (max = %d)\n",
489       hash_entry, lp_shmem_hash_size() ));
490     return False;
491   }
492
493   mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
494
495   file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
496   file_prev_p = file_scanner_p;
497   
498   while(file_scanner_p)
499   {
500     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
501     {
502       found = True;
503       break;
504     }
505     else
506     {
507       file_prev_p = file_scanner_p ;
508       file_scanner_p = (share_mode_record *)
509                          smb_shm_offset2addr(file_scanner_p->next_offset);
510     }
511   }
512   
513   if(!found)
514   {
515     /* We must create a share_mode_record */
516     share_mode_record *new_mode_p = NULL;
517     smb_shm_offset_t new_offset = smb_shm_alloc( sizeof(share_mode_record) +
518                                         strlen(fs_p->name) + 1);
519     if(new_offset == NULL_OFFSET)
520     {
521       DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n"));
522       return False;
523     }
524     new_mode_p = smb_shm_offset2addr(new_offset);
525     new_mode_p->locking_version = LOCKING_VERSION;
526     new_mode_p->st_dev = dev;
527     new_mode_p->st_ino = inode;
528     new_mode_p->num_share_mode_entries = 0;
529     new_mode_p->share_mode_entries = NULL_OFFSET;
530     strcpy(new_mode_p->file_name, fs_p->name);
531
532     /* Chain onto the start of the hash chain (in the hope we will be used first). */
533     new_mode_p->next_offset = mode_array[hash_entry];
534     mode_array[hash_entry] = new_offset;
535
536     file_scanner_p = new_mode_p;
537
538     DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
539 inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
540   }
541  
542   /* Now create the share mode entry */ 
543   new_entry_offset = smb_shm_alloc( sizeof(share_mode_entry));
544   if(new_entry_offset == NULL_OFFSET)
545   {
546     smb_shm_offset_t delete_offset = mode_array[hash_entry];
547     DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n"));
548     /* Unlink the damaged record */
549     mode_array[hash_entry] = file_scanner_p->next_offset;
550     /* And delete it */
551     smb_shm_free( delete_offset );
552     return False;
553   }
554
555   new_entry_p = smb_shm_offset2addr(new_entry_offset);
556
557   new_entry_p->pid = getpid();
558   new_entry_p->share_mode = fs_p->share_mode;
559 #ifdef USE_OPLOCKS
560   new_entry_p->op_port = port;
561   new_entry_p->op_type = op_type;
562 #endif /* USE_OPLOCKS */
563   memcpy( (char *)&new_entry_p->time, (char *)&fs_p->open_time, sizeof(struct timeval));
564
565   /* Chain onto the share_mode_record */
566   new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
567   file_scanner_p->share_mode_entries = new_entry_offset;
568
569   /* PARANOIA TEST */
570   if(file_scanner_p->num_share_mode_entries < 0)
571   {
572     DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
573 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
574          dev, inode, hash_entry));
575     return False;
576   }
577
578   /* Increment the share_mode_entries counter */
579   file_scanner_p->num_share_mode_entries += 1;
580
581   DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
582 0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->pid,
583                              file_scanner_p->num_share_mode_entries));
584
585   return(True);
586 }
587
588 #else /* FAST_SHARE_MODES */
589
590 /* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
591
592 /*******************************************************************
593   name a share file
594   ******************************************************************/
595 static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
596 {
597   strcpy(name,lp_lockdir());
598   standard_sub(cnum,name);
599   trim_string(name,"","/");
600   if (!*name) return(False);
601   name += strlen(name);
602   
603   sprintf(name,"/share.%u.%u",dev,inode);
604   return(True);
605 }
606
607 /*******************************************************************
608   lock a share mode file.
609   ******************************************************************/
610 BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
611 {
612   pstring fname;
613   int fd;
614
615   *ptok = (share_lock_token)-1;
616
617   if(!share_name(cnum, dev, inode, fname))
618     return False;
619
620   {
621     int old_umask;
622     unbecome_user();
623     old_umask = umask(0);
624 #ifdef SECURE_SHARE_MODES
625     fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0600);
626 #else /* SECURE_SHARE_MODES */
627     fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0666);
628 #endif /* SECURE_SHARE_MODES */
629     umask(old_umask);
630     if(!become_user(cnum,Connections[cnum].vuid))
631     {
632       DEBUG(0,("lock_share_entry: Can't become connected user!\n"));
633       close(fd);
634       return False;
635     }
636     /* We need to change directory back to the connection root. */
637     if (ChDir(Connections[cnum].connectpath) != 0)
638     {
639       DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n",
640               Connections[cnum].connectpath, strerror(errno)));
641       close(fd);
642       return False;  
643     }
644   }
645
646   /* At this point we have an open fd to the share mode file. 
647      Lock the first byte exclusively to signify a lock. */
648   if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
649    {
650       DEBUG(0,("ERROR lock_share_entry: fcntl_lock failed with %s\n",
651                   strerror(errno)));   
652       close(fd);
653       return False;
654    }
655
656    *ptok = (share_lock_token)fd;
657    return True;
658 }
659
660 /*******************************************************************
661   unlock a share mode file.
662   ******************************************************************/
663 BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
664 {
665   int fd = (int)token;
666   int ret = True;
667
668   /* token is the fd of the open share mode file. */
669   /* Unlock the first byte. */
670   if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
671    { 
672       DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
673                       strerror(errno)));   
674       ret = False;
675    }
676  
677   close((int)token);
678   return ret;
679 }
680
681 /*******************************************************************
682 Force a share file to be deleted.
683 ********************************************************************/
684
685 static int delete_share_file( int cnum, char *fname )
686 {
687   unbecome_user();
688   if(unlink(fname) != 0)
689   {
690     DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
691             fname, strerror(errno)));
692   }
693
694   DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
695
696   if(!become_user(cnum,Connections[cnum].vuid))
697   {
698     DEBUG(0,("delete_share_file: Can't become connected user!\n"));
699     return -1;
700   }
701   /* We need to change directory back to the connection root. */
702   if (ChDir(Connections[cnum].connectpath) != 0)
703   {
704     DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n",
705             Connections[cnum].connectpath, strerror(errno)));
706     return -1;  
707   }
708   return 0;
709 }
710
711 /*******************************************************************
712 Read a share file into a buffer.
713 ********************************************************************/
714
715 static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
716 {
717   struct stat sb;
718   char *buf;
719   int size;
720
721   *out = 0;
722   *p_new_file = False;
723
724   if(fstat(fd, &sb) != 0)
725   {
726     DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
727                   fname, strerror(errno)));
728     return -1;
729   }
730
731   if(sb.st_size == 0)
732   {
733      *p_new_file = True;
734      return 0;
735   }
736
737   /* Allocate space for the file */
738   if((buf = (char *)malloc(sb.st_size)) == NULL)
739   {
740     DEBUG(0,("read_share_file: malloc for file size %d fail !\n", sb.st_size));
741     return -1;
742   }
743   
744   if(lseek(fd, 0, SEEK_SET) != 0)
745   {
746     DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
747 for share file %s (%s)\n", fname, strerror(errno)));
748     if(buf)
749       free(buf);
750     return -1;
751   }
752   
753   if (read(fd,buf,sb.st_size) != sb.st_size)
754   {
755     DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
756                fname, strerror(errno)));
757     if(buf)
758       free(buf);
759     return -1;
760   }
761   
762   if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
763     DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
764 locking version (was %d, should be %d).\n",fname, 
765            IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION));
766     if(buf)
767       free(buf);
768     delete_share_file(cnum, fname);
769     return -1;
770   }
771
772   /* Sanity check for file contents */
773   size = sb.st_size;
774   size -= SMF_HEADER_LENGTH; /* Remove the header */
775
776   /* Remove the filename component. */
777   size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
778
779   /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
780   if((size % SMF_ENTRY_LENGTH) != 0)
781   {
782     DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
783 deleting it.\n", fname));
784     if(buf)
785       free(buf);
786     delete_share_file(cnum, fname);
787     return -1;
788   }
789
790   *out = buf;
791   return 0;
792 }
793
794 /*******************************************************************
795 get all share mode entries in a share file for a dev/inode pair.
796 ********************************************************************/
797 int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
798                     min_share_mode_entry **old_shares)
799 {
800   int fd = (int)token;
801   pstring fname;
802   int i;
803   int num_entries;
804   int num_entries_copied;
805   int newsize;
806   min_share_mode_entry *share_array;
807   char *buf = 0;
808   char *base = 0;
809   BOOL new_file;
810
811   *old_shares = 0;
812
813   /* Read the share file header - this is of the form:
814      0   -  locking version.
815      4   -  number of share mode entries.
816      8   -  2 byte name length
817      [n bytes] file name (zero terminated).
818
819    Followed by <n> share mode entries of the form :
820
821      0   -  tv_sec
822      4   -  tv_usec
823      8   -  share_mode
824     12   -  pid
825     16   -  oplock port (if oplocks in use) - 2 bytes.
826   */
827
828   share_name(cnum, dev, inode, fname);
829
830   if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
831   {
832     DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
833                   fname));
834     return 0;
835   }
836
837   if(new_file == True)
838     return 0;
839
840   num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
841
842   DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
843             fname, num_entries));
844
845   /* PARANOIA TEST */
846   if(num_entries < 0)
847   {
848     DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
849 for share file %d\n", num_entries, fname));
850     return 0;
851   }
852
853   if(num_entries)
854   {
855     *old_shares = share_array = (min_share_mode_entry *)
856                  malloc(num_entries * sizeof(min_share_mode_entry));
857     if(*old_shares == 0)
858     {
859       DEBUG(0,("get_share_modes: malloc fail !\n"));
860       return 0;
861     }
862   } 
863   else
864   {
865     /* No entries - just delete the file. */
866     DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
867               fname));
868     if(buf)
869       free(buf);
870     delete_share_file(cnum, fname);
871     return 0;
872   }
873
874   num_entries_copied = 0;
875   base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
876
877   for( i = 0; i < num_entries; i++)
878   {
879     int pid;
880     char *p = base + (i*SMF_ENTRY_LENGTH);
881
882     pid = IVAL(p,SME_PID_OFFSET);
883
884     if(!process_exists(pid))
885     {
886       DEBUG(0,("get_share_modes: process %d no longer exists and \
887 it left a share mode entry with mode 0x%X in share file %s\n",
888             pid, IVAL(p,SME_SHAREMODE_OFFSET), fname));
889       continue;
890     }
891     share_array[num_entries_copied].time.tv_sec = IVAL(p,SME_SEC_OFFSET);
892     share_array[num_entries_copied].time.tv_usec = IVAL(p,SME_USEC_OFFSET);
893     share_array[num_entries_copied].share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
894     share_array[num_entries_copied].pid = pid;
895 #ifdef USE_OPLOCKS
896     share_array[num_entries_copied].op_port = SVAL(p,SME_PORT_OFFSET);
897     share_array[num_entries_copied].op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
898 #endif /* USE_OPLOCKS */
899
900     num_entries_copied++;
901   }
902
903   if(num_entries_copied == 0)
904   {
905     /* Delete the whole file. */
906     DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
907              fname));
908     if(*old_shares)
909       free((char *)*old_shares);
910     *old_shares = 0;
911     if(buf)
912       free(buf);
913     delete_share_file(cnum, fname);
914     return 0;
915   }
916
917   /* If we deleted some entries we need to re-write the whole number of
918      share mode entries back into the file. */
919
920   if(num_entries_copied != num_entries)
921   {
922     if(lseek(fd, 0, SEEK_SET) != 0)
923     {
924       DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
925 position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
926       if(*old_shares)
927         free((char *)*old_shares);
928       *old_shares = 0;
929       if(buf)
930         free(buf);
931       return 0;
932     }
933
934     SIVAL(buf, SMF_NUM_ENTRIES_OFFSET, num_entries_copied);
935     for( i = 0; i < num_entries_copied; i++)
936     {
937       char *p = base + (i*SMF_ENTRY_LENGTH);
938
939       SIVAL(p,SME_PID_OFFSET,share_array[i].pid);
940       SIVAL(p,SME_SHAREMODE_OFFSET,share_array[i].share_mode);
941       SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
942       SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
943 #ifdef USE_OPLOCKS
944       SIVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
945       SIVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
946 #endif /* USE_OPLOCKS */
947     }
948
949     newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries_copied);
950     if(write(fd, buf, newsize) != newsize)
951     {
952       DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
953 mode file %s (%s)\n", fname, strerror(errno)));
954       if(*old_shares)
955         free((char *)*old_shares);
956       *old_shares = 0;
957       if(buf)
958         free(buf);
959       return 0;
960     }
961     /* Now truncate the file at this point. */
962     if(ftruncate(fd, newsize)!= 0)
963     {
964       DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
965 mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
966       if(*old_shares)
967         free((char *)*old_shares);
968       *old_shares = 0;
969       if(buf)
970         free(buf);
971       return 0;
972     }
973   }
974
975   if(buf)
976     free(buf);
977
978   DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
979             num_entries_copied));
980
981   return num_entries_copied;
982 }
983
984 /*******************************************************************
985 del a share mode from a share mode file.
986 ********************************************************************/
987 void del_share_mode(share_lock_token token, int fnum)
988 {
989   pstring fname;
990   int fd = (int)token;
991   char *buf = 0;
992   char *base = 0;
993   int num_entries;
994   int newsize;
995   int i;
996   files_struct *fs_p = &Files[fnum];
997   int pid;
998   BOOL deleted = False;
999   BOOL new_file;
1000
1001   share_name(fs_p->cnum, fs_p->fd_ptr->dev, 
1002                        fs_p->fd_ptr->inode, fname);
1003
1004   if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
1005   {
1006     DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
1007                   fname));
1008     return;
1009   }
1010
1011   if(new_file == True)
1012   {
1013     DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
1014               fname));
1015     delete_share_file(fs_p->cnum, fname);
1016     return;
1017   }
1018
1019   num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
1020
1021   DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
1022             fname, num_entries));
1023
1024   /* PARANOIA TEST */
1025   if(num_entries < 0)
1026   {
1027     DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
1028 for share file %d\n", num_entries, fname));
1029     return;
1030   }
1031
1032   if(num_entries == 0)
1033   {
1034     /* No entries - just delete the file. */
1035     DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
1036               fname));
1037     if(buf)
1038       free(buf);
1039     delete_share_file(fs_p->cnum, fname);
1040     return;
1041   }
1042
1043   pid = getpid();
1044
1045   /* Go through the entries looking for the particular one
1046      we have set - delete it.
1047   */
1048
1049   base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
1050
1051   for(i = 0; i < num_entries; i++)
1052   {
1053     char *p = base + (i*SMF_ENTRY_LENGTH);
1054
1055     if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) || 
1056        (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
1057        (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) || 
1058        (IVAL(p,SME_PID_OFFSET) != pid))
1059       continue;
1060
1061     DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
1062              i, num_entries, fname));
1063
1064     /* Remove this entry. */
1065     if(i != num_entries - 1)
1066       memcpy(p, p + SMF_ENTRY_LENGTH, (num_entries - i - 1)*SMF_ENTRY_LENGTH);
1067
1068     deleted = True;
1069     break;
1070   }
1071
1072   if(!deleted)
1073   {
1074     DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
1075     if(buf)
1076       free(buf);
1077     return;
1078   }
1079
1080   num_entries--;
1081   SIVAL(buf,SMF_NUM_ENTRIES_OFFSET, num_entries);
1082
1083   if(num_entries == 0)
1084   {
1085     /* Deleted the last entry - remove the file. */
1086     DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
1087              fname));
1088     if(buf)
1089       free(buf);
1090     delete_share_file(fs_p->cnum,fname);
1091     return;
1092   }
1093
1094   /* Re-write the file - and truncate it at the correct point. */
1095   if(lseek(fd, 0, SEEK_SET) != 0)
1096   {
1097     DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
1098 position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
1099     if(buf)
1100       free(buf);
1101     return;
1102   }
1103
1104   newsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
1105   if(write(fd, buf, newsize) != newsize)
1106   {
1107     DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
1108 mode file %s (%s)\n", fname, strerror(errno)));
1109     if(buf)
1110       free(buf);
1111     return;
1112   }
1113   /* Now truncate the file at this point. */
1114   if(ftruncate(fd, newsize) != 0)
1115   {
1116     DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
1117 mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
1118     if(buf)
1119       free(buf);
1120     return;
1121   }
1122 }
1123   
1124 /*******************************************************************
1125 set the share mode of a file
1126 ********************************************************************/
1127 BOOL set_share_mode(share_lock_token token,int fnum, uint16 port, uint16 op_type)
1128 {
1129   files_struct *fs_p = &Files[fnum];
1130   pstring fname;
1131   int fd = (int)token;
1132   int pid = (int)getpid();
1133   struct stat sb;
1134   char *buf;
1135   int num_entries;
1136   int header_size;
1137   char *p;
1138
1139   share_name(fs_p->cnum, fs_p->fd_ptr->dev,
1140                        fs_p->fd_ptr->inode, fname);
1141
1142   if(fstat(fd, &sb) != 0)
1143   {
1144     DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
1145                   fname));
1146     return False;
1147   }
1148
1149   /* Sanity check for file contents (if it's not a new share file). */
1150   if(sb.st_size != 0)
1151   {
1152     int size = sb.st_size;
1153
1154     /* Allocate space for the file plus one extra entry */
1155     if((buf = (char *)malloc(sb.st_size + SMF_ENTRY_LENGTH)) == NULL)
1156     {
1157       DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", 
1158                   sb.st_size + SMF_ENTRY_LENGTH));
1159       return False;
1160     }
1161  
1162     if(lseek(fd, 0, SEEK_SET) != 0)
1163     {
1164       DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
1165 to 0 for share file %s (%s)\n", fname, strerror(errno)));
1166       if(buf)
1167         free(buf);
1168       return False;
1169     }
1170
1171     if (read(fd,buf,sb.st_size) != sb.st_size)
1172     {
1173       DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
1174                   fname, strerror(errno)));
1175       if(buf)
1176         free(buf);
1177       return False;
1178     }   
1179   
1180     if (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) 
1181     {
1182       DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
1183 locking version (was %d, should be %d).\n",fname, IVAL(buf,SMF_VERSION_OFFSET), 
1184                     LOCKING_VERSION));
1185       if(buf)
1186         free(buf);
1187       delete_share_file(fs_p->cnum, fname);
1188       return False;
1189     }   
1190
1191     size -= (SMF_HEADER_LENGTH + SVAL(buf, SMF_FILENAME_LEN_OFFSET)); /* Remove the header */
1192
1193     /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
1194     if((size % SMF_ENTRY_LENGTH) != 0)
1195     {
1196       DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
1197 deleting it.\n", fname));
1198       if(buf)
1199         free(buf);
1200       delete_share_file(fs_p->cnum, fname);
1201       return False;
1202     }
1203
1204   }
1205   else
1206   {
1207     /* New file - just use a single_entry. */
1208     if((buf = (char *)malloc(SMF_HEADER_LENGTH + 
1209                   strlen(fs_p->name) + 1 + SMF_ENTRY_LENGTH)) == NULL)
1210     {
1211       DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
1212       return False;
1213     }
1214     SIVAL(buf,SMF_VERSION_OFFSET,LOCKING_VERSION);
1215     SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,0);
1216     SSVAL(buf,SMF_FILENAME_LEN_OFFSET,strlen(fs_p->name) + 1);
1217     strcpy(buf + SMF_HEADER_LENGTH, fs_p->name);
1218   }
1219
1220   num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
1221   header_size = SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
1222   p = buf + header_size + (num_entries * SMF_ENTRY_LENGTH);
1223   SIVAL(p,SME_SEC_OFFSET,fs_p->open_time.tv_sec);
1224   SIVAL(p,SME_USEC_OFFSET,fs_p->open_time.tv_usec);
1225   SIVAL(p,SME_SHAREMODE_OFFSET,fs_p->share_mode);
1226   SIVAL(p,SME_PID_OFFSET,pid);
1227 #ifdef USE_OPLOCKS
1228   SSVAL(p,SME_PORT_OFFSET,port);
1229   SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
1230 #endif /* USE_OPLOCKS */
1231
1232   num_entries++;
1233
1234   SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,num_entries);
1235
1236   if(lseek(fd, 0, SEEK_SET) != 0)
1237   {
1238     DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
1239 0 for share file %s (%s)\n", fname, strerror(errno)));
1240     if(buf)
1241       free(buf);
1242     return False;
1243   }
1244
1245   if (write(fd,buf,header_size + (num_entries*SMF_ENTRY_LENGTH)) != 
1246                        (header_size + (num_entries*SMF_ENTRY_LENGTH))) 
1247   {
1248     DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
1249 deleting it (%s).\n",fname, strerror(errno)));
1250     delete_share_file(fs_p->cnum, fname);
1251     if(buf)
1252       free(buf);
1253     return False;
1254   }
1255
1256   /* Now truncate the file at this point - just for safety. */
1257   if(ftruncate(fd, header_size + (SMF_ENTRY_LENGTH*num_entries))!= 0)
1258   {
1259     DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
1260 mode file %s to size %d (%s)\n", fname, header_size + (SMF_ENTRY_LENGTH*num_entries), 
1261                 strerror(errno)));
1262     if(buf)
1263       free(buf);
1264     return False;
1265   }
1266
1267   if(buf)
1268     free(buf);
1269
1270   DEBUG(3,("set_share_mode: Created share file %s with \
1271 mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
1272
1273   return True;
1274 }
1275 #endif /* FAST_SHARE_MODES */