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