dir.c: Fixed double slash issue.
authorSamba Release Account <samba-bugs@samba.org>
Tue, 20 May 1997 00:32:51 +0000 (00:32 +0000)
committerSamba Release Account <samba-bugs@samba.org>
Tue, 20 May 1997 00:32:51 +0000 (00:32 +0000)
includes.h: Changed to ifdef FAST_SHARE_MODES.
ipc.c:  Changed lp_workgroup() to myworkgroup.
loadparm.c:  Added new shared mem parameters. Added Luke's fix.
locking.c: Rewrite to do share modes better (both fast and slow modes).
nameannounce.c:  Changed lp_workgroup() to myworkgroup. Added Luke's fix.
nameconf.c:  Changed lp_workgroup() to myworkgroup.
namedbname.c:  Improved debug.
namedbserver.c:  Changed lp_workgroup() to myworkgroup.
namedbsubnet.c:  Added Luke's fix - rewritten somewhat.
namedbwork.c:  Changed lp_workgroup() to myworkgroup.
nameelect.c:  Added Luke's fix - rewritten somewhat.
nameresp.c:  Stoped shadowing global.
nameserv.c:  Added Luke's fix - Improved debug.
nameservreply.c:  Improved debug.
namework.c:  Changed lp_workgroup() to myworkgroup.
nmbd.c:  Added Luke's fix - Changed lp_workgroup() to myworkgroup.
pipes.c:   Changed lp_workgroup() to myworkgroup.
proto.h:   Added Luke's fix, added smb_shm_ proto's.
reply.c:  Changed lp_workgroup() to myworkgroup.
server.c:  Rewrite to do share modes better (both fast and slow modes).
shmem.c:  Rewrite to do share modes better (both fast and slow modes).
smb.h:  Rewrite to do share modes better (both fast and slow modes).
status.c:  Rewrite to do share modes better (both fast and slow modes).
trans2.c:  Fixed double slash issue.
util.c:  Tidied up, created myworkgroup.
Jeremy Allison (jallison@whistle.com).

26 files changed:
source/include/includes.h
source/include/proto.h
source/include/smb.h
source/lib/util.c
source/locking/locking.c
source/locking/shmem.c
source/nameannounce.c
source/nameconf.c
source/namedbname.c
source/namedbserver.c
source/namedbsubnet.c
source/namedbwork.c
source/nameelect.c
source/nameresp.c
source/nameserv.c
source/nameservreply.c
source/namework.c
source/nmbd/nmbd.c
source/param/loadparm.c
source/smbd/dir.c
source/smbd/ipc.c
source/smbd/pipes.c
source/smbd/reply.c
source/smbd/server.c
source/smbd/trans2.c
source/utils/status.c

index e1ed3a581683e8efff470fd202ebe7316e59b12f..265e838be0dce36d605d4df1a6cd551f197c7806 100644 (file)
@@ -481,6 +481,7 @@ char *mktemp(char *); /* No standard include */
 
 
 #ifdef FreeBSD
+#include <arpa/inet.h>
 #include <strings.h>
 #include <netinet/tcp.h>
 #include <netinet/in_systm.h>
@@ -970,7 +971,7 @@ typedef int mode_t;
 end of the platform specific sections
 ********************************************************************/
 
-#if defined(USE_MMAP) || FAST_SHARE_MODES
+#if defined(USE_MMAP) || defined(FAST_SHARE_MODES)
 #include <sys/mman.h>
 #endif
 
index 973b1a15f39dd2b2cb3ceb1195159de58da9f202..1fa8c1d95e1b6e18953ef5e676e2594fdd565658 100644 (file)
@@ -149,6 +149,7 @@ char *lp_socket_address(void);
 char *lp_nis_home_map_name(void);
 BOOL lp_wins_support(void);
 BOOL lp_wins_proxy(void);
+BOOL lp_local_master(void);
 BOOL lp_domain_master(void);
 BOOL lp_domain_logons(void);
 BOOL lp_preferred_master(void);
@@ -176,6 +177,8 @@ int lp_maxpacket(void);
 int lp_keepalive(void);
 int lp_passwordlevel(void);
 int lp_readsize(void);
+int lp_shmem_size(void);
+int lp_shmem_hash_size(void);
 int lp_deadtime(void);
 int lp_maxprotocol(void);
 int lp_security(void);
@@ -266,12 +269,12 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
 BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
 BOOL start_share_mode_mgmt(void);
 BOOL stop_share_mode_mgmt(void);
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid);
-int get_share_mode_byname(int cnum,char *fname,int *pid);
-int get_share_mode(int cnum,struct stat *sbuf,int *pid);
-void del_share_mode(int fnum);
-BOOL set_share_mode(int fnum,int mode);
-void clean_share_modes(void);
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *);
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token);
+int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
+                    min_share_mode_entry **old_shares);
+void del_share_mode(share_lock_token token, int fnum);
+BOOL set_share_mode(share_lock_token token, int fnum);
 
 /*The following definitions come from  mangle.c  */
 
@@ -309,7 +312,7 @@ void do_announce_host(int command,
                char *to_name  , int to_type  , struct in_addr to_ip,
                time_t announce_interval,
                char *server_name, int server_type, char *server_comment);
-void remove_my_servers(void);
+void announce_my_servers_removed(void);
 void announce_server(struct subnet_record *d, struct work_record *work,
                     char *name, char *comment, time_t ttl, int server_type);
 void announce_host(time_t t);
@@ -394,7 +397,7 @@ void expire_servers(time_t t);
 struct subnet_record *find_subnet(struct in_addr bcast_ip);
 struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast);
 struct subnet_record *find_subnet_all(struct in_addr bcast_ip);
-void add_subnet_interfaces(void);
+void add_workgroup_to_subnet( struct subnet_record *d, char *group);
 void add_my_subnets(char *group);
 void write_browse_list(time_t t);
 
@@ -406,7 +409,6 @@ struct work_record *remove_workgroup(struct subnet_record *d,
 struct work_record *find_workgroupstruct(struct subnet_record *d, 
                                         fstring name, BOOL add);
 void dump_workgroups(void);
-int check_work_servertype(const char *work_name, int type_mask);
 
 /*The following definitions come from  nameelect.c  */
 
@@ -724,6 +726,11 @@ BOOL smb_shm_set_userdef_off(smb_shm_offset_t userdef_off);
 void * smb_shm_offset2addr(smb_shm_offset_t offset);
 BOOL smb_shm_lock(void);
 BOOL smb_shm_unlock(void);
+smb_shm_offset_t smb_shm_alloc(int size);
+smb_shm_offset_t smb_shm_addr2offset(void *addr);
+smb_shm_offset_t smb_shm_get_userdef_off(void);
+BOOL smb_shm_lock_hash_entry( unsigned int entry);
+BOOL smb_shm_unlock_hash_entry( unsigned int entry );
 BOOL smb_shm_get_usage(int *bytes_free,
                   int *bytes_used,
                   int *bytes_overhead);
index 7cd2f5b0fef1f6c225669e2e9720c33b167771e5..e0c08183dbe114e0fc238c3eda651a0d845601e2 100644 (file)
 #define BUFFER_SIZE (0xFFFF)
 #define SAFETY_MARGIN 1024
 
-/* size of shared memory used for share mode locking */
+/* Default size of shared memory used for share mode locking */
 #ifndef SHMEM_SIZE
 #define SHMEM_SIZE 102400
 #endif
 
+/* Default number of hash buckets used in shared memory share mode */
+#ifndef SHMEM_HASH_SIZE
+#define SHMEM_HASH_SIZE 113
+#endif
+
 #define NMB_PORT 137
 #define DGRAM_PORT 138
 #define SMB_PORT 139
@@ -295,8 +300,8 @@ typedef struct
 typedef struct
 {
   uint16 ref_count;
-  int32 dev;
-  int32 inode;
+  uint32 dev;
+  uint32 inode;
   int fd;
   int fd_readonly;
   int fd_writeonly;
@@ -320,7 +325,6 @@ typedef struct
   BOOL can_read;
   BOOL can_write;
   BOOL share_mode;
-  BOOL share_pending;
   BOOL print_file;
   BOOL modified;
   char *name;
@@ -420,19 +424,40 @@ struct interface
        struct in_addr nmask;
 };
 
-/* share mode record in shared memory */
+/* share mode record pointed to in shared memory hash bucket */
 typedef struct
 {
-  smb_shm_offset_t next_offset; /* offset of next record in list in shared mem */
+  smb_shm_offset_t next_offset; /* offset of next record in chain from hash bucket */
   int locking_version;
+  int32 st_dev;
+  int32 st_ino;
+  int num_share_mode_entries;
+  smb_shm_offset_t share_mode_entries; /* Chain of share mode entries for this file */
+  char file_name[1];
+} share_mode_record;
+
+/* share mode entry pointed to by share_mode_record struct */
+typedef struct
+{
+  smb_shm_offset_t next_share_mode_entry;
+  int pid;
   int share_mode;
   struct timeval time;
+} share_mode_entry;
+
+/* struct returned by get_share_modes */
+typedef struct
+{
   int pid;
-  dev_t st_dev;
-  ino_t st_ino;
-  char file_name[1];   /* dynamically allocated with correct size */
-} share_mode_record;
+  int share_mode;
+  struct timeval time;
+} min_share_mode_entry;
+
+/* Token returned by lock_share_entry (actually ignored by FAST_SHARE_MODES code) */
+typedef int share_lock_token;
 
+/* Conversion to hash entry index from device and inode numbers. */
+#define HASH_ENTRY(dev,ino) ((( (uint32)(dev) )* ( (uint32)(ino) )) % lp_shmem_hash_size())
 
 /* this is used for smbstatus */
 struct connect_record
@@ -798,12 +823,15 @@ char *Strstr(char *s, char *p);
 #define SV_TYPE_DOMAIN_ENUM         0x80000000
 #define SV_TYPE_ALL                 0xFFFFFFFF  
 
-/* What server type are we currently  - JHT Says we ARE 4.20 */
+/* what server type are we currently  - JHT Says we ARE 4.20 */
+/* this was set by JHT in liaison with Jeremy Allison early 1997 */
+/* setting to 4.20 at same time as announcing ourselves as NT Server */
 /* History: */
 /* Version 4.0 - never made public */
 /* Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9 */
 /*             - Reappeared in 1.9.16p11 with fixed smbd services */
 /* Version 4.20 - To indicate that nmbd and browsing now works better */
+
 #define MAJOR_VERSION 0x04
 #define MINOR_VERSION 0x02
 
index 3315f1a41a1758fcd47b8fa6dc4eb80a97d08ce7..0ed08405ba7775aec0b305f52557fdd62b6eab27 100644 (file)
@@ -73,6 +73,7 @@ pstring myhostname="";
 pstring user_socket_options="";   
 pstring sesssetup_user="";
 pstring myname = "";
+fstring myworkgroup = "";
 
 int smb_read_error = 0;
 
@@ -3431,7 +3432,7 @@ BOOL is_vetoed_name(char *name)
           nameptr++;
           continue;
         }
-      if(name_end = strchr(nameptr,'/')
+      if((name_end = strchr(nameptr,'/'))!=NULL
         {
           *name_end = 0;
         }
@@ -3472,7 +3473,7 @@ BOOL is_vetoed_path(char *name)
           nameptr++;
           continue;
         }
-      if(name_end = strchr(nameptr,'/')
+      if((name_end = strchr(nameptr,'/'))!=NULL
         {
           *name_end = 0;
         }
index 7c23e5b3cabdbc84a37c60c2e2ccf9ebbb3daab5..e63e347a262ebbf2df46e9e09cf7ca62271cd26b 100644 (file)
@@ -22,6 +22,9 @@
 
    12 aug 96: Erik.Devriendt@te6.siemens.be
    added support for shared memory implementation of share mode locking
+
+   May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
+   locking to deal with multiple share modes per open file.
 */
 
 #include "includes.h"
@@ -29,9 +32,6 @@ extern int DEBUGLEVEL;
 extern connection_struct Connections[];
 extern files_struct Files[];
 
-pstring share_del_pending="";
-
-
 /****************************************************************************
   utility function called to see if a file region is locked
 ****************************************************************************/
@@ -100,7 +100,7 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
   return True; /* Did unlock */
 }
 
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
 /*******************************************************************
   initialize the shared memory for share_mode management 
   ******************************************************************/
@@ -114,7 +114,7 @@ BOOL start_share_mode_mgmt(void)
   trim_string(shmem_file_name,"","/");
   if (!*shmem_file_name) return(False);
   strcat(shmem_file_name, "/SHARE_MEM_FILE");
-  return smb_shm_open(shmem_file_name, SHMEM_SIZE);
+  return smb_shm_open(shmem_file_name, lp_shmem_size());
 }
 
 
@@ -126,459 +126,1118 @@ BOOL stop_share_mode_mgmt(void)
    return smb_shm_close();
 }
 
-#else
-
-/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
-
-/*******************************************************************
-  name a share file
-  ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
-{
-  strcpy(name,lp_lockdir());
-  standard_sub(cnum,name);
-  trim_string(name,"","/");
-  if (!*name) return(False);
-  name += strlen(name);
-  
-  sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
-  return(True);
-}
-
 /*******************************************************************
-  use the fnum to get the share file name
+  lock a hash bucket entry in shared memory for share_mode management 
   ******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
 {
-  struct stat st;
-  if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
-  return(share_name(Files[fnum].cnum,&st,name));
+  return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
 }
 
-#endif
-
 /*******************************************************************
-  get the share mode of a file using the fnum
+  unlock a hash bucket entry in shared memory for share_mode management 
   ******************************************************************/
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
 {
-  struct stat sbuf;
-  if (fstat(Files[fnum].fd_ptr->fd,&sbuf) == -1) return(0);
-  return(get_share_mode(cnum,&sbuf,pid));
+  return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
 }
 
 /*******************************************************************
-  get the share mode of a file using the files name
-  ******************************************************************/
-int get_share_mode_byname(int cnum,char *fname,int *pid)
-{
-  struct stat sbuf;
-  if (stat(fname,&sbuf) == -1) return(0);
-  return(get_share_mode(cnum,&sbuf,pid));
-}  
-
-
-/*******************************************************************
-get the share mode of a file
+get all share mode entries in shared memory for a dev/inode pair.
 ********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
+                    min_share_mode_entry **old_shares)
 {
-#if FAST_SHARE_MODES
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
-  int ret;
+  smb_shm_offset_t *mode_array;
+  unsigned int hash_entry = HASH_ENTRY(dev, inode); 
+  share_mode_record *file_scanner_p;
+  share_mode_record *file_prev_p;
+  share_mode_entry *entry_scanner_p;
+  share_mode_entry *entry_prev_p;
+  int num_entries;
+  int num_entries_copied;
   BOOL found = False;
+  min_share_mode_entry *share_array = (min_share_mode_entry *)0;
 
-  *pid = 0;
+  *old_shares = 0;
 
-  if(!smb_shm_lock()) return (0);
+  if(hash_entry > lp_shmem_hash_size() )
+  {
+    DEBUG(0, 
+      ("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+      hash_entry, lp_shmem_hash_size() ));
+    abort();
+  }
 
-  scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
+  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+  
+  if(mode_array[hash_entry] == NULL_OFFSET)
   {
-     if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) )
+    DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
+    return 0;
+  }
+
+  file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+  file_prev_p = file_scanner_p;
+  while(file_scanner_p)
+  {
+     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
      {
        found = True;
        break;
      }
      else
      {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
+       file_prev_p = file_scanner_p ;
+       file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
+                                                file_scanner_p->next_offset);
      }
   }
   
   if(!found)
   {
-     smb_shm_unlock();
+     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
+file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
      return (0);
   }
   
-  if(scanner_p->locking_version != LOCKING_VERSION)
+  if(file_scanner_p->locking_version != LOCKING_VERSION)
   {
-     DEBUG(2,("Deleting old share mode record due to old locking version %d",scanner_p->locking_version));
-     if(prev_p == scanner_p)
-       smb_shm_set_userdef_off(scanner_p->next_offset);
+     DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev = %d, inode = %d in hash \
+bucket %d",file_scanner_p->locking_version, dev, inode, hash_entry));
+     if(file_prev_p == file_scanner_p)
+       mode_array[hash_entry] = file_scanner_p->next_offset;
      else
-       prev_p->next_offset = scanner_p->next_offset;
-     smb_shm_free(smb_shm_addr2offset(scanner_p));
-     *pid = 0;
-       
-     smb_shm_unlock();
+       file_prev_p->next_offset = file_scanner_p->next_offset;
+     smb_shm_free(smb_shm_addr2offset(file_scanner_p));
      return (0);
   }
-  
-  *pid = scanner_p->pid;
-  ret = scanner_p->share_mode;
 
-  if (*pid && !process_exists(*pid))
+  /* Allocate the old_shares array */
+  num_entries = file_scanner_p->num_share_mode_entries;
+  if(num_entries)
   {
-    ret = 0;
-    *pid = 0;
+    *old_shares = share_array = (min_share_mode_entry *)
+                 malloc(num_entries * sizeof(min_share_mode_entry));
+    if(*old_shares == 0)
+    {
+      DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
+      return 0;
+    }
   }
+
+  num_entries_copied = 0;
   
-  if (! *pid)
+  entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+                                           file_scanner_p->share_mode_entries);
+  entry_prev_p = entry_scanner_p;
+  while(entry_scanner_p)
   {
-     if(prev_p == scanner_p)
-       smb_shm_set_userdef_off(scanner_p->next_offset);
-     else
-       prev_p->next_offset = scanner_p->next_offset;
-     smb_shm_free(smb_shm_addr2offset(scanner_p));
+    int pid = entry_scanner_p->pid;
+
+    if (pid && !process_exists(pid))
+    {
+      /* Delete this share mode entry */
+      share_mode_entry *delete_entry_p = entry_scanner_p;
+
+      if(entry_prev_p == entry_scanner_p)
+      {
+        /* We are at start of list */
+        file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+        entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+                                           file_scanner_p->share_mode_entries);
+        entry_prev_p = entry_scanner_p;
+      }
+      else
+      {
+        entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+        entry_scanner_p = (share_mode_entry*)
+                           smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+      }
+      /* Decrement the number of share mode entries on this share mode record */
+      file_scanner_p->num_share_mode_entries -= 1;
+
+      /* PARANOIA TEST */
+      if(file_scanner_p->num_share_mode_entries < 0)
+      {
+        DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+             dev, inode, hash_entry));
+        abort();
+      }
+
+      DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
+it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
+bucket (number of entries now = %d)\n", 
+            pid, entry_scanner_p->share_mode, dev, inode, hash_entry,
+            file_scanner_p->num_share_mode_entries));
+
+      smb_shm_free(smb_shm_addr2offset(delete_entry_p));
+    } 
+    else
+    {
+       /* This is a valid share mode entry and the process that
+           created it still exists. Copy it into the output array.
+       */
+       share_array[num_entries_copied].pid = entry_scanner_p->pid;
+       share_array[num_entries_copied].share_mode = entry_scanner_p->share_mode;
+       memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->time,
+              sizeof(struct timeval));
+       num_entries_copied++;
+       DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
+record mode 0x%X pid=%d\n", entry_scanner_p->share_mode, entry_scanner_p->pid));
+       entry_prev_p = entry_scanner_p;
+       entry_scanner_p = (share_mode_entry *)
+                           smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+    }
   }
   
-  if (*pid)
-    DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid));
+  /* If no valid share mode entries were found then this record shouldn't exist ! */
+  if(num_entries_copied == 0)
+  {
+    DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d has a share mode record but no entries - deleting\n", 
+                 dev, inode, hash_entry));
+    if(*old_shares)
+      free((char *)old_shares);
+    *old_shares = 0;
+
+    if(file_prev_p == file_scanner_p)
+      mode_array[hash_entry] = file_scanner_p->next_offset;
+    else
+      file_prev_p->next_offset = file_scanner_p->next_offset;
+    smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+  }
 
-  if(!smb_shm_unlock()) return (0);
-  
-  return(ret);
-  
-#else
-  pstring fname;
-  int fd2;
-  char buf[20];
-  int ret;
-  struct timeval t;
+  DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d returning %d entries\n", dev, inode, hash_entry,
+                         num_entries_copied));
+
+  return(num_entries_copied);
+}  
 
-  *pid = 0;
+/*******************************************************************
+del the share mode of a file.
+********************************************************************/
+void del_share_mode(share_lock_token token, int fnum)
+{
+  uint32 dev, inode;
+  smb_shm_offset_t *mode_array;
+  unsigned int hash_entry;
+  share_mode_record *file_scanner_p;
+  share_mode_record *file_prev_p;
+  share_mode_entry *entry_scanner_p;
+  share_mode_entry *entry_prev_p;
+  BOOL found = False;
+  int pid = getpid();
 
-  if (!share_name(cnum,sbuf,fname)) return(0);
+  dev = Files[fnum].fd_ptr->dev;
+  inode = Files[fnum].fd_ptr->inode;
 
-  fd2 = open(fname,O_RDONLY,0);
-  if (fd2 < 0) return(0);
+  hash_entry = HASH_ENTRY(dev, inode);
 
-  if (read(fd2,buf,20) != 20) {
-    DEBUG(2,("Failed to read share file %s\n",fname));
-    close(fd2);
-    unlink(fname);
-    return(0);
+  if(hash_entry > lp_shmem_hash_size() )
+  {
+    DEBUG(0,
+      ("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+      hash_entry, lp_shmem_hash_size() ));
+    abort();
   }
-  close(fd2);
 
-  t.tv_sec = IVAL(buf,4);
-  t.tv_usec = IVAL(buf,8);
-  ret = IVAL(buf,12);
-  *pid = IVAL(buf,16);
+  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+  if(mode_array[hash_entry] == NULL_OFFSET)
+  {  
+    DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n", 
+                  hash_entry));
+    abort();
+  }  
   
-  if (IVAL(buf,0) != LOCKING_VERSION) {    
-    if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
-    *pid = 0;
-    return(0);
-  }
+  file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+  file_prev_p = file_scanner_p;
 
-  if (*pid && !process_exists(*pid)) {
-    ret=0;
-    *pid = 0;
+  while(file_scanner_p)
+  {
+     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
+     {
+       found = True;
+       break;
+     }
+     else
+     {
+       file_prev_p = file_scanner_p ;
+       file_scanner_p = (share_mode_record *)
+                          smb_shm_offset2addr(file_scanner_p->next_offset);
+     }
+  }
+    
+  if(!found)
+  {
+     DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+     return;
+  }
+  
+  if(file_scanner_p->locking_version != LOCKING_VERSION)
+  {
+     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
+       file_scanner_p->locking_version, dev, inode, hash_entry ));
+     if(file_prev_p == file_scanner_p)
+       mode_array[hash_entry] = file_scanner_p->next_offset;
+     else
+       file_prev_p->next_offset = file_scanner_p->next_offset;
+     smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+     return;
   }
 
-  if (! *pid) unlink(fname); /* XXXXX race, race */
+  found = False;
+  entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+                                           file_scanner_p->share_mode_entries);
+  entry_prev_p = entry_scanner_p;
+  while(entry_scanner_p)
+  {
+    if( (pid == entry_scanner_p->pid) && 
+          (memcmp(&entry_scanner_p->time, 
+                 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+    {
+      found = True;
+      break;
+    }
+    else
+    {
+      entry_prev_p = entry_scanner_p;
+      entry_scanner_p = (share_mode_entry *)
+                          smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+    }
+  } 
 
-  if (*pid)
-    DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
+  if (found)
+  {
+    /* Decrement the number of entries in the record. */
+    file_scanner_p->num_share_mode_entries -= 1;
+
+    DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
+Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
+              dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
+    if(entry_prev_p == entry_scanner_p)
+      /* We are at start of list */
+      file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
+    else
+      entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
+    smb_shm_free(smb_shm_addr2offset(entry_scanner_p));
+
+    /* PARANOIA TEST */
+    if(file_scanner_p->num_share_mode_entries < 0)
+    {
+      DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+           dev, inode, hash_entry));
+      abort();
+    }
 
-  return(ret);
-#endif
+    /* If we deleted the last share mode entry then remove the share mode record. */
+    if(file_scanner_p->num_share_mode_entries == 0)
+      {
+      DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
+record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+      if(file_prev_p == file_scanner_p)
+       mode_array[hash_entry] = file_scanner_p->next_offset;
+      else
+       file_prev_p->next_offset = file_scanner_p->next_offset;
+      smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+      }
+  }
+  else
+  {
+    DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
+dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+  }
 }
 
-
 /*******************************************************************
-del the share mode of a file, if we set it last
+set the share mode of a file. Return False on fail, True on success.
 ********************************************************************/
-void del_share_mode(int fnum)
+BOOL set_share_mode(share_lock_token token, int fnum)
 {
-#if FAST_SHARE_MODES
-  struct stat st;
-  struct timeval t;
-  int pid=0;
-  BOOL del = False;
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
+  files_struct *fs_p = &Files[fnum];
+  int32 dev, inode;
+  smb_shm_offset_t *mode_array;
+  unsigned int hash_entry;
+  share_mode_record *file_scanner_p;
+  share_mode_record *file_prev_p;
+  share_mode_entry *new_entry_p;
+  smb_shm_offset_t new_entry_offset;
   BOOL found = False;
 
-  t.tv_sec = t.tv_usec = 0;
-  
-  if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return;
-  
-  if (!smb_shm_lock()) return;
+  dev = fs_p->fd_ptr->dev;
+  inode = fs_p->fd_ptr->inode;
+
+  hash_entry = HASH_ENTRY(dev, inode);
+  if(hash_entry > lp_shmem_hash_size() )
+  {
+    DEBUG(0,
+      ("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+      hash_entry, lp_shmem_hash_size() ));
+    abort();
+  }
+
+  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+  file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+  file_prev_p = file_scanner_p;
   
-  scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
+  while(file_scanner_p)
   {
-     if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
+     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
      {
-       found = True;
-       break;
+        found = True;
+        break;
      }
      else
      {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
+        file_prev_p = file_scanner_p ;
+        file_scanner_p = (share_mode_record *)
+                          smb_shm_offset2addr(file_scanner_p->next_offset);
      }
   }
-    
+  
   if(!found)
   {
-     smb_shm_unlock();
-     return;
+    /* We must create a share_mode_record */
+    share_mode_record *new_mode_p = NULL;
+    smb_shm_offset_t new_offset = smb_shm_alloc( sizeof(share_mode_record) +
+                                        strlen(fs_p->name) + 1);
+    if(new_offset == NULL_OFFSET)
+    {
+      DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n"));
+      return False;
+    }
+    new_mode_p = smb_shm_offset2addr(new_offset);
+    new_mode_p->locking_version = LOCKING_VERSION;
+    new_mode_p->st_dev = dev;
+    new_mode_p->st_ino = inode;
+    new_mode_p->num_share_mode_entries = 0;
+    new_mode_p->share_mode_entries = NULL_OFFSET;
+    strcpy(new_mode_p->file_name, fs_p->name);
+
+    /* Chain onto the start of the hash chain (in the hope we will be used first). */
+    new_mode_p->next_offset = mode_array[hash_entry];
+    mode_array[hash_entry] = new_offset;
+
+    file_scanner_p = new_mode_p;
+
+    DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
+inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
+  }
+  /* Now create the share mode entry */ 
+  new_entry_offset = smb_shm_alloc( sizeof(share_mode_entry));
+  if(new_entry_offset == NULL_OFFSET)
+  {
+    smb_shm_offset_t delete_offset = mode_array[hash_entry];
+    DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n"));
+    /* Unlink the damaged record */
+    mode_array[hash_entry] = file_scanner_p->next_offset;
+    /* And delete it */
+    smb_shm_free( delete_offset );
+    return False;
   }
-  
-  t.tv_sec = scanner_p->time.tv_sec;
-  t.tv_usec = scanner_p->time.tv_usec;
-  pid = scanner_p->pid;
-  
-  if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
-    del = True;
 
-  if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0)
-      && pid==(int)getpid())
-    del = True;
+  new_entry_p = smb_shm_offset2addr(new_entry_offset);
 
-  if (del)
+  new_entry_p->pid = getpid();
+  new_entry_p->share_mode = fs_p->share_mode;
+  memcpy( (char *)&new_entry_p->time, (char *)&fs_p->open_time, sizeof(struct timeval));
+
+  /* Chain onto the share_mode_record */
+  new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
+  file_scanner_p->share_mode_entries = new_entry_offset;
+
+  /* PARANOIA TEST */
+  if(file_scanner_p->num_share_mode_entries < 0)
   {
-     DEBUG(2,("Deleting share mode record\n"));
-     if(prev_p == scanner_p)
-       smb_shm_set_userdef_off(scanner_p->next_offset);
-     else
-       prev_p->next_offset = scanner_p->next_offset;
-     smb_shm_free(smb_shm_addr2offset(scanner_p));
-       
+    DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+         dev, inode, hash_entry));
+    abort();
   }
 
-  smb_shm_unlock();
-  return;
+  /* Increment the share_mode_entries counter */
+  file_scanner_p->num_share_mode_entries += 1;
+
+  DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
+0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->pid,
+                             file_scanner_p->num_share_mode_entries));
+
+  return(True);
+}
+
+#else /* FAST_SHARE_MODES */
+
+/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
 
-#else
+/*******************************************************************
+  name a share file
+  ******************************************************************/
+static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
+{
+  strcpy(name,lp_lockdir());
+  standard_sub(cnum,name);
+  trim_string(name,"","/");
+  if (!*name) return(False);
+  name += strlen(name);
+  
+  sprintf(name,"/share.%u.%u",dev,inode);
+  return(True);
+}
+
+/*******************************************************************
+  lock a share mode file.
+  ******************************************************************/
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
+{
   pstring fname;
-  int fd2;
-  char buf[20];
-  struct timeval t;
-  int pid=0;
-  BOOL del = False;
-
-  t.tv_sec = t.tv_usec = 0;
-  if (!share_name_fnum(fnum,fname)) return;
-
-  fd2 = open(fname,O_RDONLY,0);
-  if (fd2 < 0) return;
-  if (read(fd2,buf,20) != 20)
-    del = True;
-  close(fd2);
-
-  if (!del) {
-    t.tv_sec = IVAL(buf,4);
-    t.tv_usec = IVAL(buf,8);
-    pid = IVAL(buf,16);
-  }
-
-  if (!del)
-    if (IVAL(buf,0) != LOCKING_VERSION || !pid || !process_exists(pid))
-      del = True;
-
-  if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0) && (pid==(int)getpid()))
-    del = True;
-
-  if (del) {
-    if (!unlink(fname)) 
-      DEBUG(2,("Deleted share file %s\n",fname));
-    else {
-      DEBUG(3,("Pending delete share file %s\n",fname));
-      if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
-      strcpy(share_del_pending,fname);
+  int fd;
+
+  *ptok = (share_lock_token)-1;
+
+  if(!share_name(cnum, dev, inode, fname))
+    return False;
+
+  {
+    int old_umask;
+    unbecome_user();
+    old_umask = umask(0);
+#ifdef SECURE_SHARE_MODES
+    fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0600);
+#else /* SECURE_SHARE_MODES */
+    fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0644);
+#endif /* SECURE_SHARE_MODES */
+    umask(old_umask);
+    if(!become_user(cnum,Connections[cnum].vuid))
+    {
+      DEBUG(0,("lock_share_entry: Can't become connected user!\n"));
+      close(fd);
+      return False;
+    }
+    /* We need to change directory back to the connection root. */
+    if (ChDir(Connections[cnum].connectpath) != 0)
+    {
+      DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n",
+              Connections[cnum].connectpath, strerror(errno)));
+      close(fd);
+      return False;  
     }
   }
-#endif
+
+  /* At this point we have an open fd to the share mode file. 
+     Lock the first byte exclusively to signify a lock. */
+  if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+   {
+      DEBUG(0,("ERROR lock_share_entry: fcntl_lock failed with %s\n",
+                  strerror(errno)));   
+      close(fd);
+      return False;
+   }
+
+   *ptok = (share_lock_token)fd;
+   return True;
 }
-  
 
 /*******************************************************************
-set the share mode of a file
+  unlock a share mode file.
+  ******************************************************************/
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+{
+  int fd = (int)token;
+  int ret = True;
+
+  /* token is the fd of the open share mode file. */
+  /* Unlock the first byte. */
+  if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+   { 
+      DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
+                      strerror(errno)));   
+      ret = False;
+   }
+  close((int)token);
+  return ret;
+}
+
+/*******************************************************************
+Force a share file to be deleted.
 ********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+
+static int delete_share_file( int cnum, char *fname )
 {
-#if FAST_SHARE_MODES
-  int pid = (int)getpid();
-  struct stat st;
-  smb_shm_offset_t new_off;
-  share_mode_record *new_p;
+  unbecome_user();
+  if(unlink(fname) != 0)
+  {
+    DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
+            fname, strerror(errno)));
+  }
+
+  DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
+
+  if(!become_user(cnum,Connections[cnum].vuid))
+  {
+    DEBUG(0,("delete_share_file: Can't become connected user!\n"));
+    return -1;
+  }
+  /* We need to change directory back to the connection root. */
+  if (ChDir(Connections[cnum].connectpath) != 0)
+  {
+    DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n",
+            Connections[cnum].connectpath, strerror(errno)));
+    return -1;  
+  }
+  return 0;
+}
+
+/*******************************************************************
+Read a share file into a buffer.
+********************************************************************/
+
+static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
+{
+  struct stat sb;
+  char *buf;
+  int size;
+
+  *out = 0;
+  *p_new_file = False;
+
+  if(fstat(fd, &sb) != 0)
+  {
+    DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
+                  fname, strerror(errno)));
+    return -1;
+  }
+
+  if(sb.st_size == 0)
+  {
+     *p_new_file = True;
+     return 0;
+  }
+
+  /* Allocate space for the file */
+  if((buf = (char *)malloc(sb.st_size)) == NULL)
+  {
+    DEBUG(0,("read_share_file: malloc for file size %d fail !\n", sb.st_size));
+    return -1;
+  }
   
+  if(lseek(fd, 0, SEEK_SET) != 0)
+  {
+    DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
+for share file %s (%s)\n", fname, strerror(errno)));
+    if(buf)
+      free(buf);
+    return -1;
+  }
   
-  if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
+  if (read(fd,buf,sb.st_size) != sb.st_size)
+  {
+    DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
+               fname, strerror(errno)));
+    if(buf)
+      free(buf);
+    return -1;
+  }
   
-  if (!smb_shm_lock()) return (False);
-  new_off = smb_shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
-  if (new_off == NULL_OFFSET) return (False);
-  new_p = (share_mode_record *)smb_shm_offset2addr(new_off);
-  new_p->locking_version = LOCKING_VERSION;
-  new_p->share_mode = mode;
-  new_p->time.tv_sec = Files[fnum].open_time.tv_sec;
-  new_p->time.tv_usec = Files[fnum].open_time.tv_usec;
-  new_p->pid = pid;
-  new_p->st_dev = st.st_dev;
-  new_p->st_ino = st.st_ino;
-  strcpy(new_p->file_name,Files[fnum].name);
-  new_p->next_offset = smb_shm_get_userdef_off();
-  smb_shm_set_userdef_off(new_off);
-
-
-  DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
-
-  if (!smb_shm_unlock()) return (False);
-  return(True);
+  if (IVAL(buf,0) != LOCKING_VERSION) {
+    DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
+    if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return -1;
+  }
+
+  /* Sanity check for file contents */
+  size = sb.st_size;
+  size -= 10; /* Remove the header */
+
+  /* Remove the filename component. */
+  size -= SVAL(buf, 8);
+
+  /* The remaining size must be a multiple of 16 - error if not. */
+  if((size % 16) != 0)
+  {
+    DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
+deleting it.\n", fname));
+    if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return -1;
+  }
 
-#else
+  *out = buf;
+  return 0;
+}
+
+/*******************************************************************
+get all share mode entries in a share file for a dev/inode pair.
+********************************************************************/
+int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
+                    min_share_mode_entry **old_shares)
+{
+  int fd = (int)token;
   pstring fname;
-  int fd2;
-  char buf[20];
-  int pid = (int)getpid();
+  int i;
+  int num_entries;
+  int num_entries_copied;
+  int newsize;
+  min_share_mode_entry *share_array;
+  char *buf = 0;
+  char *base = 0;
+  BOOL new_file;
+
+  *old_shares = 0;
+
+  /* Read the share file header - this is of the form:
+     0   -  locking version.
+     4   -  number of share mode entries.
+     8   -  2 byte name length
+     [n bytes] file name (zero terminated).
 
-  if (!share_name_fnum(fnum,fname)) return(False);
+   Followed by <n> share mode entries of the form :
 
+     0   -  tv_sec
+     4   -  tv_usec
+     8   -  share_mode
+    12   -  pid
+
+  */
+
+  share_name(cnum, dev, inode, fname);
+
+  if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
   {
-    int old_umask = umask(0);
-    fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
-    umask(old_umask);
+    DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
+                  fname));
+    return 0;
   }
-  if (fd2 < 0) {
-    DEBUG(2,("Failed to create share file %s\n",fname));
-    return(False);
+
+  if(new_file == True)
+    return 0;
+
+  num_entries = IVAL(buf,4);
+
+  DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
+            fname, num_entries));
+
+  /* PARANOIA TEST */
+  if(num_entries < 0)
+  {
+    DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+    abort();
   }
 
-  SIVAL(buf,0,LOCKING_VERSION);
-  SIVAL(buf,4,Files[fnum].open_time.tv_sec);
-  SIVAL(buf,8,Files[fnum].open_time.tv_usec);
-  SIVAL(buf,12,mode);
-  SIVAL(buf,16,pid);
+  if(num_entries)
+  {
+    *old_shares = share_array = (min_share_mode_entry *)
+                 malloc(num_entries * sizeof(min_share_mode_entry));
+    if(*old_shares == 0)
+    {
+      DEBUG(0,("get_share_modes: malloc fail !\n"));
+      return 0;
+    }
+  } 
+  else
+  {
+    /* No entries - just delete the file. */
+    DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
+              fname));
+    if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return 0;
+  }
 
-  if (write(fd2,buf,20) != 20) {
-    DEBUG(2,("Failed to write share file %s\n",fname));
-    close(fd2);
-    unlink(fname);
-    return(False);
+  num_entries_copied = 0;
+  base = buf + 10 + SVAL(buf,8);
+
+  for( i = 0; i < num_entries; i++)
+  {
+    int pid;
+    char *p = base + (i*16);
+
+    pid = IVAL(p,12);
+
+    if(!process_exists(pid))
+    {
+      DEBUG(0,("get_share_modes: process %d no longer exists and \
+it left a share mode entry with mode 0x%X in share file %s\n",
+            pid, IVAL(p,8), fname));
+      continue;
+    }
+    share_array[num_entries_copied].time.tv_sec = IVAL(p,0);
+    share_array[num_entries_copied].time.tv_usec = IVAL(p,4);
+    share_array[num_entries_copied].share_mode = IVAL(p,8);
+    share_array[num_entries_copied].pid = pid;
+
+    num_entries_copied++;
   }
 
-  write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+  if(num_entries_copied == 0)
+  {
+    /* Delete the whole file. */
+    DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
+             fname));
+    if(*old_shares)
+      free((char *)old_shares);
+    if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return 0;
+  }
 
-  close(fd2);
+  /* If we deleted some entries we need to re-write the whole number of
+     share mode entries back into the file. */
 
-  DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+  if(num_entries_copied != num_entries)
+  {
+    if(lseek(fd, 0, SEEK_SET) != 0)
+    {
+      DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+      if(*old_shares)
+        free((char *)old_shares);
+      if(buf)
+        free(buf);
+      return 0;
+    }
 
-  return(True);
-#endif
+    SIVAL(buf, 4, num_entries_copied);
+    for( i = 0; i < num_entries_copied; i++)
+    {
+      char *p = base + (i*16);
+
+      SIVAL(p,12,share_array[i].pid);
+      SIVAL(p,8,share_array[i].share_mode);
+      SIVAL(p,0,share_array[i].time.tv_sec);
+      SIVAL(p,4,share_array[i].time.tv_usec);
+    }
+
+    newsize = (base - buf) + (16*num_entries_copied);
+    if(write(fd, buf, newsize) != newsize)
+    {
+      DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+      if(*old_shares)
+        free((char *)old_shares);
+      if(buf)
+        free(buf);
+      return 0;
+    }
+    /* Now truncate the file at this point. */
+    if(ftruncate(fd, newsize)!= 0)
+    {
+      DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+      if(*old_shares)
+        free((char *)old_shares);
+      if(buf)
+        free(buf);
+      return 0;
+    }
+  }
+
+  if(buf)
+    free(buf);
+
+  DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
+            num_entries_copied));
+
+  return num_entries_copied;
 }
-  
 
 /*******************************************************************
-cleanup any stale share files
+del a share mode from a share mode file.
 ********************************************************************/
-void clean_share_modes(void)
+void del_share_mode(share_lock_token token, int fnum)
 {
-#ifdef USE_SHMEM
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
+  pstring fname;
+  int fd = (int)token;
+  char *buf = 0;
+  char *base = 0;
+  int num_entries;
+  int newsize;
+  int i;
+  files_struct *fs_p = &Files[fnum];
   int pid;
-  
-  if (!smb_shm_lock()) return;
-  
-  scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
+  BOOL deleted = False;
+  BOOL new_file;
+
+  share_name(fs_p->cnum, fs_p->fd_ptr->dev, 
+                       fs_p->fd_ptr->inode, fname);
+
+  if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
   {
-     pid = scanner_p->pid;
-     
-     if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
-     {
-       DEBUG(2,("Deleting stale share mode record"));
-       if(prev_p == scanner_p)
-       {
-          smb_shm_set_userdef_off(scanner_p->next_offset);
-          smb_shm_free(smb_shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-           prev_p = scanner_p;
-       }
-       else
-       {
-          prev_p->next_offset = scanner_p->next_offset;
-          smb_shm_free(smb_shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)smb_shm_offset2addr(prev_p->next_offset);
-       }
-       
-     }
-     else
-     {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
-     }
+    DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
+                  fname));
+    return;
   }
-    
 
-  smb_shm_unlock();
-  return;
-  
-#else
-  char *lockdir = lp_lockdir();
-  void *dir;
-  char *s;
+  if(new_file == True)
+  {
+    DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
+              fname));
+    delete_share_file(fs_p->cnum, fname);
+    return;
+  }
 
-  if (!*lockdir) return;
+  num_entries = IVAL(buf,4);
 
-  dir = opendir(lockdir);
-  if (!dir) return;
+  DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
+            fname, num_entries));
 
-  while ((s=readdirname(dir))) {
-    char buf[20];
-    int pid;
-    int fd;
-    pstring lname;
-    int dev,inode;
+  /* PARANOIA TEST */
+  if(num_entries < 0)
+  {
+    DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+    abort();
+  }
 
-    if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
+  if(num_entries == 0)
+  {
+    /* No entries - just delete the file. */
+    DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
+              fname));
+    if(buf)
+      free(buf);
+    delete_share_file(fs_p->cnum, fname);
+    return;
+  }
 
-    strcpy(lname,lp_lockdir());
-    trim_string(lname,NULL,"/");
-    strcat(lname,"/");
-    strcat(lname,s);
+  pid = getpid();
 
-    fd = open(lname,O_RDONLY,0);
-    if (fd < 0) continue;
+  /* Go through the entries looking for the particular one
+     we have set - delete it.
+  */
 
-    if (read(fd,buf,20) != 20) {
-      close(fd);
-      if (!unlink(lname))
-       printf("Deleted corrupt share file %s\n",s);
+  base = buf + 10 + SVAL(buf,8);
+
+  for(i = 0; i < num_entries; i++)
+  {
+    char *p = base + (i*16);
+
+    if((IVAL(p,0) != fs_p->open_time.tv_sec) || (IVAL(p,4) != fs_p->open_time.tv_usec) ||
+        (IVAL(p,8) != fs_p->share_mode) || (IVAL(p,12) != pid))
       continue;
+
+    DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
+             i, num_entries, fname));
+
+    /* Remove this entry. */
+    if(i != num_entries - 1)
+      memcpy(p, p + 16, (num_entries - i - 1)*16);
+
+    deleted = True;
+    break;
+  }
+
+  if(!deleted)
+  {
+    DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
+    if(buf)
+      free(buf);
+    return;
+  }
+
+  num_entries--;
+  SIVAL(buf,4, num_entries);
+
+  if(num_entries == 0)
+  {
+    /* Deleted the last entry - remove the file. */
+    DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
+             fname));
+    if(buf)
+      free(buf);
+    delete_share_file(fs_p->cnum,fname);
+    return;
+  }
+
+  /* Re-write the file - and truncate it at the correct point. */
+  if(lseek(fd, 0, SEEK_SET) != 0)
+    {
+      DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+      if(buf)
+        free(buf);
+      return;
     }
-    close(fd);
 
-    pid = IVAL(buf,16);
+  newsize = (base - buf) + (16*num_entries);
+  if(write(fd, buf, newsize) != newsize)
+    {
+      DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+      if(buf)
+        free(buf);
+      return;
+    }
+  /* Now truncate the file at this point. */
+  if(ftruncate(fd, newsize) != 0)
+  {
+    DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+    if(buf)
+      free(buf);
+    return;
+  }
+}
+  
+/*******************************************************************
+set the share mode of a file
+********************************************************************/
+BOOL set_share_mode(share_lock_token token,int fnum)
+{
+  files_struct *fs_p = &Files[fnum];
+  pstring fname;
+  int fd = (int)token;
+  int pid = (int)getpid();
+  struct stat sb;
+  char *buf;
+  int num_entries;
+  int header_size;
+  char *p;
+
+  share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+                       fs_p->fd_ptr->inode, fname);
+
+  if(fstat(fd, &sb) != 0)
+  {
+    DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
+                  fname));
+    return False;
+  }
 
-    if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) {
-      if (!unlink(lname))
-       printf("Deleted stale share file %s\n",s);
+  /* Sanity check for file contents (if it's not a new share file). */
+  if(sb.st_size != 0)
+  {
+    int size = sb.st_size;
+
+    /* Allocate space for the file plus one extra entry */
+    if((buf = (char *)malloc(sb.st_size + 16)) == NULL)
+    {
+      DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", sb.st_size + 16));
+      return False;
+    }
+    if(lseek(fd, 0, SEEK_SET) != 0)
+    {
+      DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
+to 0 for share file %s (%s)\n", fname, strerror(errno)));
+      if(buf)
+        free(buf);
+      return False;
     }
+
+    if (read(fd,buf,sb.st_size) != sb.st_size)
+    {
+      DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
+                  fname, strerror(errno)));
+      if(buf)
+        free(buf);
+      return False;
+    }   
+  
+    if (IVAL(buf,0) != LOCKING_VERSION) 
+    {
+      DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
+      if(buf)
+        free(buf);
+      delete_share_file(fs_p->cnum, fname);
+      return False;
+    }   
+
+    size -= (10 + SVAL(buf, 8)); /* Remove the header */
+
+    /* The remaining size must be a multiple of 16 - error if not. */
+    if((size % 16) != 0)
+    {
+      DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
+deleting it.\n", fname));
+      if(buf)
+        free(buf);
+      delete_share_file(fs_p->cnum, fname);
+      return False;
+    }
+
   }
+  else
+  {
+    /* New file - just use a single_entry. */
+    if((buf = (char *)malloc(10 + strlen(fs_p->name) + 1 + 16)) == NULL)
+    {
+      DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
+      return False;
+    }
+    SIVAL(buf,0,LOCKING_VERSION);
+    SIVAL(buf,4,0);
+    SSVAL(buf,8,strlen(fs_p->name) + 1);
+    strcpy(buf + 10, fs_p->name);
+  }
+
+  num_entries = IVAL(buf,4);
+  header_size = 10 + SVAL(buf,8);
+  p = buf + header_size + (num_entries * 16);
+  SIVAL(p,0,fs_p->open_time.tv_sec);
+  SIVAL(p,4,fs_p->open_time.tv_usec);
+  SIVAL(p,8,fs_p->share_mode);
+  SIVAL(p,12,pid);
+
+  num_entries++;
+
+  SIVAL(buf,4,num_entries);
+
+  if(lseek(fd, 0, SEEK_SET) != 0)
+  {
+    DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
+0 for share file %s (%s)\n", fname, strerror(errno)));
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  if (write(fd,buf,header_size + (num_entries*16)) != (header_size + (num_entries*16))) 
+  {
+    DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
+deleting it (%s).\n",fname, strerror(errno)));
+    delete_share_file(fs_p->cnum, fname);
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  /* Now truncate the file at this point - just for safety. */
+  if(ftruncate(fd, header_size + (16*num_entries))!= 0)
+  {
+    DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, header_size + (16*num_entries), strerror(errno)));
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  if(buf)
+    free(buf);
+
+  DEBUG(3,("set_share_mode: Created share file %s with \
+mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
 
-  closedir(dir);
-#endif
+  return True;
 }
+#endif /* FAST_SHARE_MODES */
index 2c02982d04a3368414dfec434b86b50b897d574d..9d4e62bdd789c21656a783bb172f7008d3e31981 100644 (file)
@@ -23,7 +23,7 @@
 #include "includes.h"
 
 
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
 
 
 extern int DEBUGLEVEL;
@@ -32,7 +32,7 @@ extern int DEBUGLEVEL;
 #define SMB_SHM_MAGIC 0x53484100
 /* = "SHM" in hex */
 
-#define SMB_SHM_VERSION 1
+#define SMB_SHM_VERSION 2
 
 /* WARNING : offsets are used because mmap() does not guarantee that all processes have the 
    shared memory mapped to the same address */
@@ -73,15 +73,109 @@ static pstring smb_shm_processreg_name = "";
 static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
 static int smb_shm_times_locked = 0;
 
+static BOOL smb_shm_initialize_called = False;
+
+static BOOL smb_shm_global_lock(void)
+{
+   if (smb_shm_fd < 0)
+   {
+      DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+      return False;
+   }
+   
+   smb_shm_times_locked++;
+   
+   if(smb_shm_times_locked > 1)
+   {
+      DEBUG(2,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
+      return True;
+   }
+   
+   /* Do an exclusive wait lock on the first byte of the file */
+   if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+   {
+      DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %d\n",errno));
+      smb_shm_times_locked--;
+      return False;
+   }
+   
+   return True;
+   
+}
+
+static BOOL smb_shm_global_unlock(void)
+{
+   if (smb_shm_fd < 0)
+   {
+      DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+      return False;
+   }
+   
+   if(smb_shm_times_locked == 0)
+   {
+      DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n",smb_shm_fd));
+      return False;
+   }
+   
+   smb_shm_times_locked--;
+   
+   if(smb_shm_times_locked > 0)
+   {
+      DEBUG(2,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
+      return True;
+   }
+   
+   /* Do a wait unlock on the first byte of the file */
+   if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+   {
+      DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %d\n",errno));
+      smb_shm_times_locked++;
+      return False;
+   }
+   
+   return True;
+   
+}
+
+/* 
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+
+BOOL smb_shm_create_hash_table( unsigned int size )
+{
+  size *= sizeof(smb_shm_offset_t);
+
+  smb_shm_global_lock();
+  smb_shm_header_p->userdef_off = smb_shm_alloc( size );
+
+  if(smb_shm_header_p->userdef_off == NULL_OFFSET)
+    {
+      DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
+      smb_shm_global_unlock();
+      return False;
+    }
+
+  /* Clear hash buckets. */
+  memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
+  smb_shm_global_unlock();
+  return True;
+}
+
 static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
 {
    int smb_shm_processes_fd = -1;
    int nb_read;
    pid_t other_pid;
+   int seek_back = -sizeof(other_pid);
    int free_slot = -1;
    int erased_slot;   
    
+#ifndef SECURE_SHARE_MODES
    smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0666);
+#else /* SECURE_SHARE_MODES */
+   smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0600);
+#endif /* SECURE_SHARE_MODES */
    if ( smb_shm_processes_fd < 0 )
    {
       DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %d\n",errno));
@@ -99,9 +193,10 @@ static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *oth
         else
         {
            /* erase old pid */
-            DEBUG(2,("smb_shm_register_process : erasing stale record for pid %d\n",other_pid));
+            DEBUG(2,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %d)\n",
+                      other_pid, seek_back));
            other_pid = (pid_t)0;
-           erased_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+           erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
            write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
            if(free_slot < 0)
               free_slot = erased_slot;
@@ -109,7 +204,7 @@ static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *oth
       }
       else 
         if(free_slot < 0)
-           free_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+           free_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
    }
    if (nb_read < 0)
    {
@@ -141,6 +236,7 @@ static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
    int smb_shm_processes_fd = -1;
    int nb_read;
    pid_t other_pid;
+   int seek_back = -sizeof(other_pid);
    int erased_slot;
    BOOL found = False;
    
@@ -156,12 +252,14 @@ static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
    
    while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
    {
+      DEBUG(2,("smb_shm_unregister_process : read record for pid %d\n",other_pid));
       if(other_pid == pid)
       {
         /* erase pid */
-         DEBUG(2,("smb_shm_unregister_process : erasing record for pid %d\n",other_pid));
+         DEBUG(2,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %d)\n",
+                     other_pid, seek_back));
         other_pid = (pid_t)0;
-        erased_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+        erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
         if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
         {
            DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %d\n",errno));
@@ -257,6 +355,8 @@ static BOOL smb_shm_initialize(int size)
    
    smb_shm_header_p->consistent = True;
    
+   smb_shm_initialize_called = True;
+
    return True;
 }
    
@@ -291,7 +391,11 @@ BOOL smb_shm_open( char *file_name, int size)
    DEBUG(2,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size));
 
    old_umask = umask(0);
+#ifndef SECURE_SHARE_MODES
    smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0666);
+#else /* SECURE_SHARE_MODES */
+   smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0600);
+#endif /* SECURE_SHARE_MODE */
    umask(old_umask);
    if ( smb_shm_fd < 0 )
    {
@@ -299,16 +403,16 @@ BOOL smb_shm_open( char *file_name, int size)
       return False;
    }
    
-   if (!smb_shm_lock())
+   if (!smb_shm_global_lock())
    {
-      DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_lock\n"));
+      DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
       return False;
    }
    
    if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0)
    {
       DEBUG(0,("ERROR smb_shm_open : lseek failed with code %d\n",errno));
-      smb_shm_unlock();
+      smb_shm_global_unlock();
       close(smb_shm_fd);
       return False;
    }
@@ -332,7 +436,7 @@ BOOL smb_shm_open( char *file_name, int size)
 
    if (! smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
    {
-      smb_shm_unlock();
+      smb_shm_global_unlock();
       close(smb_shm_fd);
       return False;
    }
@@ -344,7 +448,7 @@ BOOL smb_shm_open( char *file_name, int size)
       {
          DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %d\n",errno));
         smb_shm_unregister_process(smb_shm_processreg_name, getpid());
-        smb_shm_unlock();
+        smb_shm_global_unlock();
         close(smb_shm_fd);
         return False;
       }
@@ -369,7 +473,7 @@ BOOL smb_shm_open( char *file_name, int size)
    {
       DEBUG(0,("ERROR smb_shm_open : mmap failed with code %d\n",errno));
       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
-      smb_shm_unlock();
+      smb_shm_global_unlock();
       close(smb_shm_fd);
       return False;
    }      
@@ -378,6 +482,8 @@ BOOL smb_shm_open( char *file_name, int size)
    if (created_new || !other_processes)
    {
       smb_shm_initialize(size);
+      /* Create the hash buckets for the share file entries. */
+      smb_shm_create_hash_table( lp_shmem_hash_size() );
    }
    else if (!smb_shm_validate_header(size) )
    {
@@ -385,12 +491,12 @@ BOOL smb_shm_open( char *file_name, int size)
       DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
       munmap((caddr_t)smb_shm_header_p, size);
       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
-      smb_shm_unlock();
+      smb_shm_global_unlock();
       close(smb_shm_fd);
       return False;
    }
    
-   smb_shm_unlock();
+   smb_shm_global_unlock();
    return True;
       
 }
@@ -399,17 +505,22 @@ BOOL smb_shm_open( char *file_name, int size)
 BOOL smb_shm_close( void )
 {
    
+   if(smb_shm_initialize_called == False)
+     return True;
+
    DEBUG(2,("smb_shm_close\n"));
    if(smb_shm_times_locked > 0)
       DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
-   if ( munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0)
+   if ((smb_shm_header_p != NULL) && 
+              (munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
    {
       DEBUG(0,("ERROR smb_shm_close : munmap failed with code %d\n",errno));
    }
 
-   smb_shm_lock();
+   smb_shm_global_lock();
+   DEBUG(2,("calling smb_shm_unregister_process(%s, %d)\n", smb_shm_processreg_name, getpid()));
    smb_shm_unregister_process(smb_shm_processreg_name, getpid());
-   smb_shm_unlock();
+   smb_shm_global_unlock();
    
    close(smb_shm_fd);
    
@@ -438,9 +549,12 @@ smb_shm_offset_t smb_shm_alloc(int size)
       return NULL_OFFSET;
    }
    
+   smb_shm_global_lock();
+
    if( !smb_shm_header_p->consistent)
    {
       DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
+      smb_shm_global_unlock();
       return NULL_OFFSET;
    }
    
@@ -463,6 +577,7 @@ smb_shm_offset_t smb_shm_alloc(int size)
    if ( scanner_p == EOList_Addr )     
    {
       DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
+      smb_shm_global_unlock();
       return (NULL_OFFSET);
    }
    
@@ -516,6 +631,7 @@ smb_shm_offset_t smb_shm_alloc(int size)
 
    DEBUG(2,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
 
+   smb_shm_global_unlock();
    return ( result_offset );
 }   
 
@@ -534,9 +650,12 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
       return False;
    }
    
+   smb_shm_global_lock();
+
    if( !smb_shm_header_p->consistent)
    {
       DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
+      smb_shm_global_unlock();
       return False;
    }
    
@@ -545,6 +664,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
    if (header_p->next != SMB_SHM_NOT_FREE_OFF)
    {
       DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
+      smb_shm_global_unlock();
       return False;
    }
    
@@ -577,6 +697,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
       smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
       
       smb_shm_header_p->consistent = True;
+      smb_shm_global_unlock();
       return True;
    } 
    else
@@ -590,6 +711,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
       smb_shm_solve_neighbors(prev_p) ;
 
       smb_shm_header_p->consistent = True;
+      smb_shm_global_unlock();
       return True;
    }
 }
@@ -633,68 +755,71 @@ smb_shm_offset_t smb_shm_addr2offset(void *addr)
    return (smb_shm_offset_t)((char *)addr - (char *)smb_shm_header_p);
 }
 
-BOOL smb_shm_lock(void)
+/*******************************************************************
+  Lock a particular hash bucket entry.
+  ******************************************************************/
+
+BOOL smb_shm_lock_hash_entry( unsigned int entry)
 {
-   if (smb_shm_fd < 0)
-   {
-      DEBUG(0,("ERROR smb_shm_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+  int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
+
+  if (smb_shm_fd < 0)
+    {
+      DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
       return False;
-   }
-   
-   smb_shm_times_locked++;
-   
-   if(smb_shm_times_locked > 1)
-   {
-      DEBUG(2,("smb_shm_lock : locked %d times\n",smb_shm_times_locked));
-      return True;
-   }
-   
-   if (lockf(smb_shm_fd, F_LOCK, 0) < 0)
-   {
-      DEBUG(0,("ERROR smb_shm_lock : lockf failed with code %d\n",errno));
-      smb_shm_times_locked--;
+    }
+
+  if(entry >= lp_shmem_hash_size())
+    {
+      DEBUG(0,("ERROR smb_shm_lock_hash_entry : hash entry size too big (%d)\n", entry));
       return False;
-   }
-   
-   return True;
-   
+    }
+  
+  /* Do an exclusive wait lock on the 4 byte region mapping into this entry  */
+  if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_WRLCK) == False)
+    {
+      DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %d\n",errno));
+      return False;
+    }
+  
+  DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry)); 
+  return True;
 }
 
+/*******************************************************************
+  Unlock a particular hash bucket entry.
+  ******************************************************************/
 
-
-BOOL smb_shm_unlock(void)
+BOOL smb_shm_unlock_hash_entry( unsigned int entry )
 {
-   if (smb_shm_fd < 0)
-   {
-      DEBUG(0,("ERROR smb_shm_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+  int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
+
+  if (smb_shm_fd < 0)
+    {
+      DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
       return False;
-   }
+    }
    
-   if(smb_shm_times_locked == 0)
-   {
-      DEBUG(0,("ERROR smb_shm_unlock : shmem not locked\n",smb_shm_fd));
+  if(entry >= lp_shmem_hash_size())
+    {
+      DEBUG(0,("ERROR smb_shm_unlock_hash_entry : hash entry size too big (%d)\n", entry));
       return False;
-   }
-   
-   smb_shm_times_locked--;
-   
-   if(smb_shm_times_locked > 0)
-   {
-      DEBUG(2,("smb_shm_unlock : still locked %d times\n",smb_shm_times_locked));
-      return True;
-   }
-   
-   if (lockf(smb_shm_fd, F_ULOCK, 0) < 0)
-   {
-      DEBUG(0,("ERROR smb_shm_unlock : lockf failed with code %d\n",errno));
-      smb_shm_times_locked++;
+    }
+
+  /* Do a wait lock on the 4 byte region mapping into this entry  */
+  if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_UNLCK) == False)
+    {
+      DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %d\n",errno));
       return False;
-   }
-   
-   return True;
-   
+    }
+  
+  DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry)); 
+  return True;
 }
 
+/*******************************************************************
+  Gather statistics on shared memory usage.
+  ******************************************************************/
 
 BOOL smb_shm_get_usage(int *bytes_free,
                   int *bytes_used,
@@ -716,4 +841,4 @@ BOOL smb_shm_get_usage(int *bytes_free,
 #else /* FAST_SHARE_MODES */
  int shmem_dummy_procedure(void)
 {return 0;}
-#endif
+#endif /* FAST_SHARE_MODES */
index b46436168c3996986cb5df5717d7cb14d6978a18..7d7a95334c97b4302e963514a8a78fe18d6b7385 100644 (file)
@@ -35,6 +35,7 @@ extern BOOL CanRecurse;
 extern struct in_addr ipzero;
 
 extern pstring myname;
+extern fstring myworkgroup;
 
 extern int ClientDGRAM;
 extern int ClientNMB;
@@ -185,9 +186,9 @@ void do_announce_host(int command,
 
 
 /****************************************************************************
-  remove all samba's server entries
-  ****************************************************************************/
-void remove_my_servers(void)
+announce all samba's server entries as 'gone'.
+****************************************************************************/
+void announce_my_servers_removed(void)
 {
        struct subnet_record *d; 
        for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
@@ -372,7 +373,7 @@ static time_t announce_timer_last=0;
 
 void reset_announce_timer()
 {
-  announce_timer_last = 0;
+  announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
 }
 
 /****************************************************************************
@@ -396,7 +397,7 @@ void announce_master(time_t t)
       return;
     }
 
-  if(wins_subnet == 0)
+  if(wins_subnet == NULL)
     {
       DEBUG(10,("announce_master: no wins subnet, ignoring.\n"));
       return;
@@ -412,19 +413,19 @@ void announce_master(time_t t)
          if (AM_MASTER(work))
            {
              am_master = True;
+              DEBUG(4,( "announce_master: am_master = %d for \
+workgroup %s\n", am_master, work->work_group));
            }
        }
     }
  
-  DEBUG(4,( "announce_master: am_master = %d for workgroup %s\n", am_master, lp_workgroup()));
-
   if (!am_master) return; /* only proceed if we are a master browser */
   
   /* Note that we don't do this if we are domain master browser
      and that we *only* do this on the WINS subnet. */
 
   /* Try and find our workgroup on the WINS subnet */
-  work = find_workgroupstruct(wins_subnet, lp_workgroup(), False);
+  work = find_workgroupstruct(wins_subnet, myworkgroup, False);
 
   if (work)
     {
@@ -488,7 +489,7 @@ in our own WINS database.\n", work->work_group));
 
            /* Check that this isn't one of our addresses (ie. we are not domain master
               ourselves) */
-           if(ismyip(nr->ip_flgs[0].ip))
+           if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero))
              {
                DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \
 is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) ));
@@ -535,7 +536,7 @@ void announce_remote(time_t t)
   if (!*s) return;
 
   comment = lp_serverstring();
-  workgroup = lp_workgroup();
+  workgroup = myworkgroup;
 
   for (ptr=s; next_token(&ptr,s2,NULL); ) {
     /* the entries are of the form a.b.c.d/WORKGROUP with 
index 99951a3b0ea77c065f01962768712521e8b830be..8f33419b9ac708c19b394eb8c9702b0dc93dbd29 100644 (file)
@@ -35,6 +35,8 @@
 #include "includes.h"
 extern int DEBUGLEVEL;
 
+extern fstring myworkgroup;
+
 #if 0
 struct smbbrowse_parms
     {
@@ -104,7 +106,7 @@ static struct smbbrowse *new_workgroup(struct smbbrowse *model,
     StrnCpy(new->work_name, workgroup_name, 15);
     strupper(new->work_name);
         
-       if (strequal(lp_workgroup(), workgroup_name))
+       if (strequal(myworkgroup, workgroup_name))
       StrnCpy(new->browsing_alias, default_name, 15);
     else
       sprintf(new->browsing_alias, "%.14s%x", default_name, nexttoken);
@@ -289,7 +291,7 @@ static void default_smbbrowse_conf(char *default_name)
     struct smbbrowse *w;
     
     /* The workgroup specified in smb.conf */
-    w = new_workgroup((struct smbbrowse *)NULL, lp_workgroup(), default_name);
+    w = new_workgroup((struct smbbrowse *)NULL, myworkgroup, default_name);
     w->should_local_master = lp_preferred_master();
     w->should_domain_master = lp_domain_master();
     w->should_workgroup_member = True;
index 2e0afc1497baee4a0815a5895d1dba775dbfaf9c..aa41726450f4b190cc985fac0dedef21dc73d4f4 100644 (file)
@@ -153,11 +153,13 @@ struct name_record *find_name(struct name_record *n,
                        {
                                continue;
                        }
-                       DEBUG(9,("find_name: found name %s\n", name->name));
+                       DEBUG(9,("find_name: found name %s(%02x)\n", 
+                                  name->name, name->name_type));
                        return ret;
                }
        }
-    DEBUG(9,("find_name: name %s NOT FOUND\n", name->name));
+    DEBUG(9,("find_name: name %s(%02x) NOT FOUND\n", name->name, 
+              name->name_type));
     return NULL;
 }
 
@@ -528,7 +530,6 @@ struct name_record *dns_name_search(struct nmb_name *question, int Time)
 {
        int name_type = question->name_type;
        char *qname = question->name;
-       char *r;
        BOOL dns_type = (name_type == 0x20 || name_type == 0);
        struct in_addr dns_ip;
 
index 9c7bb664ab23fda93c7e25ad36b50c717f6209ca..8cad8a3a1126d6c6de9e883402eb35199287156b 100644 (file)
@@ -37,6 +37,7 @@ extern int ClientDGRAM;
 extern int DEBUGLEVEL;
 
 extern pstring myname;
+extern fstring myworkgroup;
 
 /* this is our domain/workgroup/server database */
 extern struct subnet_record *subnetlist;
@@ -161,7 +162,7 @@ struct server_record *add_server_entry(struct subnet_record *d,
   }
   
   
-  if (strequal(lp_workgroup(),work->work_group))
+  if (strequal(myworkgroup,work->work_group))
     {
          if (servertype)
         servertype |= SV_TYPE_LOCAL_LIST_ONLY;
index 25c369ab1c8800eb513db1f11e25ae1ffad72812..393db363d8689a2cf082fe2e468faf71b0dccd38 100644 (file)
@@ -40,6 +40,7 @@ extern struct in_addr wins_ip;
 extern struct in_addr ipzero;
 
 extern pstring myname;
+extern fstring myworkgroup;
 
 BOOL updatedlists = True;
 int updatecount = 0;
@@ -52,15 +53,10 @@ struct subnet_record *subnetlist = NULL;
 
 /* WINS subnet - keep this separate so enumeration code doesn't
    run onto it by mistake. */
-struct subnet_record *wins_subnet = 0;
+struct subnet_record *wins_subnet = NULL;
 
 extern uint16 nb_type; /* samba's NetBIOS name type */
 
-/* Forward references. */
-static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, 
-                                      struct in_addr mask_ip,
-                                      char *name, BOOL add, BOOL lmhosts);
-
 /****************************************************************************
   add a domain into the list
   **************************************************************************/
@@ -129,6 +125,7 @@ struct subnet_record *find_subnet_all(struct in_addr bcast_ip)
   struct subnet_record *d = find_subnet(bcast_ip);
   if(!d)
     return wins_subnet;
+  return d;
 }
 
 /****************************************************************************
@@ -156,121 +153,122 @@ static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr
   return d;
 }
 
-
 /****************************************************************************
-  add the remote interfaces from lp_interfaces()
-  to the netbios subnet database.
+  add a domain entry. creates a workgroup, if necessary, and adds the domain
+  to the named a workgroup.
   ****************************************************************************/
-void add_subnet_interfaces(void)
+static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, 
+                                      struct in_addr mask_ip, char *name, 
+                                       BOOL create_subnets, BOOL add)
 {
-  struct interface *i;
+  struct subnet_record *d = NULL;
 
-  /* loop on all local interfaces */
-  for (i = local_interfaces; i; i = i->next)
-    {
-      /* add the interface into our subnet database */
-      if (!find_subnet(i->bcast))
-       {
-         make_subnet(i->bcast,i->nmask, True);
-       }
-    }
+  if (zero_ip(bcast_ip)) 
+    bcast_ip = *iface_bcast(bcast_ip);
+  
+  /* Note that we should also add into the WINS subnet as add_subnet_entry
+    should be called to add NetBIOS names and server entries on all
+    interfaces, including the WINS interface
+   */
 
-  /* add the pseudo-ip interface for WINS: 255.255.255.255 */
-  if (lp_wins_support() || (*lp_wins_server()))
+  if(create_subnets == True)
+  {
+    /* Create new subnets. */
+    if((d = make_subnet(bcast_ip, mask_ip, add)) == NULL)
     {
-      struct in_addr wins_bcast = wins_ip;
-      struct in_addr wins_nmask = ipzero;
-      wins_subnet = make_subnet(wins_bcast, wins_nmask, False);
+      DEBUG(0,("add_subnet_entry: Unable to create subnet %s\n",
+               inet_ntoa(bcast_ip) ));
+      return NULL;
     }
+    return d;
+  }
+  if(ip_equal(bcast_ip, wins_ip))
+    return wins_subnet;
+  return find_subnet(bcast_ip);
 }
 
-
-
 /****************************************************************************
-  add the default workgroup into the subnet lists.
-  **************************************************************************/
-void add_my_subnets(char *group)
+ Add a workgroup into a subnet, and if it's our primary workgroup,
+ add the required names to it.
+**************************************************************************/
+
+void add_workgroup_to_subnet( struct subnet_record *d, char *group)
 {
-  struct interface *i;
+  struct work_record *w = NULL;
 
-  /* add or find domain on our local subnet, in the default workgroup */
-  
-  if (*group == '*') return;
+  DEBUG(5,("add_workgroup_to_subnet: Adding workgroup %s to subnet %s\n",
+            group, inet_ntoa(d->bcast_ip)));
 
-       /* the coding choice is up to you, andrew: i can see why you don't want
-       global access to the local_interfaces structure: so it can't get
-       messed up! */
-    for (i = local_interfaces; i; i = i->next)
-    {
-      add_subnet_entry(i->bcast,i->nmask,group, True, False);
-    }
+  /* This next statement creates the workgroup struct if it doesn't
+     already exist. 
+   */
+  if((w = find_workgroupstruct(d, group, True)) == NULL)
+  {
+    DEBUG(0,("add_workgroup_to_subnet: Unable to add workgroup %s to subnet %s\n",
+              group, inet_ntoa(d->bcast_ip) ));
+    return;
+  }
 
-    /* If we are setup as a domain master browser, and are using
-       WINS, then we must add the workgroup to the WINS subnet. This
-       is used as a place to keep collated server lists. */
-
-    if(lp_domain_master() && (lp_wins_support() || lp_wins_server()))
-      if(find_workgroupstruct(wins_subnet, group, True) == 0)
-        DEBUG(0, ("add_my_subnets: Failed to add workgroup %s to \
-WINS subnet.\n", group));
-      else
-        DEBUG(3,("add_my_subnets: Added workgroup %s to WINS subnet.\n",
-                 group));
+  /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
+     or register with WINS server, if it's our workgroup 
+   */
+  if (strequal(myworkgroup, group))
+  {
+    add_my_name_entry(d,group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
+    add_my_name_entry(d,group,0x0 ,nb_type|NB_ACTIVE|NB_GROUP);
+    /* add samba server name to workgroup list. */
+    add_server_entry(d,w,myname,w->ServerType,0,lp_serverstring(),True);
+    DEBUG(3,("add_workgroup_to_subnet: Added server name entry %s to subnet %s\n",
+                myname, inet_ntoa(d->bcast_ip)));
+  }
 }
 
-
 /****************************************************************************
-  add a domain entry. creates a workgroup, if necessary, and adds the domain
-  to the named a workgroup.
-  ****************************************************************************/
-static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, 
-                                      struct in_addr mask_ip,
-                                      char *name, BOOL add, BOOL lmhosts)
-{
-  struct subnet_record *d;
+  create subnet / workgroup / server entries
+     
+  - add or create the subnet lists
+  - add or create the workgroup entries in each subnet entry
+  - register appropriate NetBIOS names for the workgroup entries
+     
+**************************************************************************/
+void add_my_subnets(char *group)
+{    
+  static BOOL create_subnets = True;
+  struct subnet_record *d = NULL;
+  struct interface *i = NULL;
 
-  /* XXXX andrew: struct in_addr ip appears not to be referenced at all except
-     in the DEBUG comment. i assume that the DEBUG comment below actually
-     intends to refer to bcast_ip? i don't know.
+  if (*group == '*') return;
 
-  struct in_addr ip = wins_ip;
+  /* Create subnets from all the local interfaces and thread them onto
+     the linked list. 
+   */
+  for (i = local_interfaces; i; i = i->next)
+  {
+    add_subnet_entry(i->bcast,i->nmask,group, create_subnets, True);
+  }
 
-  */
+  /* If we are using WINS, then we must add the workgroup to the WINS
+     subnet. This is used as a place to keep collated server lists.
+   */
 
-  if (zero_ip(bcast_ip)) 
-    bcast_ip = *iface_bcast(bcast_ip);
-  
-  /* add the domain into our domain database */
-  /* Note that we never add into the WINS subnet as add_subnet_entry
-     is only called to add our local interfaces. */
-  if ((d = find_subnet(bcast_ip)) ||
-      (d = make_subnet(bcast_ip, mask_ip, True)))
-    {
-      struct work_record *w = find_workgroupstruct(d, name, add);
-      
-      if (!w) return NULL;
+  /* Create the WINS subnet if we are using WINS - but don't thread it
+     onto the linked subnet list. 
+   */    
+  if (lp_wins_support() || lp_wins_server())
+  {
+    struct in_addr wins_nmask = ipzero;
+    wins_subnet = add_subnet_entry(wins_ip, wins_nmask, group, create_subnets, False);
+  }
 
-      /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
-        or register with WINS server, if it's our workgroup */
-      if (strequal(lp_workgroup(), name))
-       {
-         add_my_name_entry(d,name,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
-         add_my_name_entry(d,name,0x0 ,nb_type|NB_ACTIVE|NB_GROUP);
-       }
-      /* add samba server name to workgroup list. don't add
-         lmhosts server entries to local interfaces */
-      if (strequal(lp_workgroup(), name))
-      {
-       add_server_entry(d,w,myname,w->ServerType,0,lp_serverstring(),True);
-        DEBUG(3,("Added server name entry %s at %s\n",
-                  name,inet_ntoa(bcast_ip)));
-      }
-      
-      return d;
-    }
-  return NULL;
-}
+  /* Ensure we only create the subnets once. */
+  create_subnets = False;
 
+  /* Now we have created all the subnets - we can add the names
+     that make us a client member in the workgroup.
+   */
+  for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+    add_workgroup_to_subnet(d, group);
+}
 
 /*******************************************************************
   write out browse.dat
index 8c249cc82cbac20b825a4ffb9e32b9761be01eb8..d752916815f20a5157da1b9a12272d346886e5eb 100644 (file)
@@ -40,6 +40,8 @@ extern struct subnet_record *subnetlist;
 
 extern struct in_addr wins_ip;
 
+extern fstring myworkgroup;
+
 int workgroup_count = 0; /* unique index key: one for each workgroup */
 
 
@@ -192,8 +194,8 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
   if ((work = make_workgroup(name)))
     {
       if (!ip_equal(d->bcast_ip, wins_ip) &&
-         lp_preferred_master() &&
-         strequal(lp_workgroup(), name))
+         lp_preferred_master() && lp_local_master() &&
+         strequal(myworkgroup, name))
        {
          DEBUG(3, ("preferred master startup for %s\n", work->work_group));
          work->needelection = True;
index 02fda9f817ba84d8db67af1565ac39954c1761d1..82cebd3e6c5df8c135209cf8138a0f0f1e0b6323 100644 (file)
@@ -40,6 +40,7 @@ extern int DEBUGLEVEL;
 extern pstring scope;
 
 extern pstring myname;
+extern fstring myworkgroup;
 extern struct in_addr ipzero;
 extern struct in_addr wins_ip;
 
@@ -57,55 +58,59 @@ extern uint16 nb_type; /* samba's NetBIOS name type */
   ******************************************************************/
 void check_master_browser(time_t t)
 {
-       static time_t lastrun=0;
-       struct subnet_record *d;
+  static time_t lastrun=0;
+  struct subnet_record *d;
 
-       if (!lastrun) lastrun = t;
-       if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
+  if (!lastrun) lastrun = t;
+  if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
 
-       lastrun = t;
+  lastrun = t;
 
-       dump_workgroups();
+  dump_workgroups();
 
-       for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
-       {
-               struct work_record *work;
+  for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+  {
+    struct work_record *work;
 
-               for (work = d->workgrouplist; work; work = work->next)
-               {
-                       if (strequal(work->work_group, lp_workgroup()) && !AM_MASTER(work))
-                       {
-                               if (lp_preferred_master())
-                               {
-                                       /* preferred master - not a master browser.  force
-                                          becoming a master browser, hence the log message.
-                                        */
-
-                                       DEBUG(0,("%s preferred master for %s %s - force election\n",
-                                                 timestring(), work->work_group,
-                                                 inet_ntoa(d->bcast_ip)));
-
-                                       browser_gone(work->work_group, d->bcast_ip);
-                               }
-                               else
-                               {
-                                       /* if we are not the browse master of a workgroup,
-                                          and we can't find a browser on the subnet, do
-                                          something about it.
-                                        */
-
-                                       queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
-                                                    work->work_group,0x1d,0,0,0,NULL,NULL,
-                                                    True,False,d->bcast_ip,d->bcast_ip);
-                               }
-                       }
-               }
-       }
+    for (work = d->workgrouplist; work; work = work->next)
+    {
+      if (strequal(work->work_group, myworkgroup) && !AM_MASTER(work))
+      {
+        if (lp_local_master())
+        {
+          /* potential master browser - not a master browser.  force
+             becoming a master browser, hence the log message.
+           */
+
+          DEBUG(0,("%s potential master for %s %s - force election\n",
+                   timestring(), work->work_group,
+                   inet_ntoa(d->bcast_ip)));
+
+          browser_gone(work->work_group, d->bcast_ip);
+        }
+        else
+        {
+          /* if we are not the browse master of a workgroup,
+             and we can't find a browser on the subnet, do
+             something about it.
+           */
+
+          queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+                    work->work_group,0x1d,0,0,0,NULL,NULL,
+                    True,False,d->bcast_ip,d->bcast_ip);
+        }
+      }
+    }
+  }
 }
 
 
 /*******************************************************************
-  what to do if a master browser DOESN't exist
+  what to do if a master browser DOESN't exist.
+
+  option 1: force an election, and participate in it
+  option 2: force an election, and let everyone else participate.
+
   ******************************************************************/
 void browser_gone(char *work_name, struct in_addr ip)
 {
@@ -119,24 +124,37 @@ void browser_gone(char *work_name, struct in_addr ip)
   if (ip_equal(d->bcast_ip,wins_ip)) 
     return;
 
-  if (strequal(work->work_group, lp_workgroup()))
+  if (strequal(work->work_group, myworkgroup))
   {
 
+    if (lp_local_master())
+    {
+      /* we have discovered that there is no local master
+         browser, and we are configured to initiate
+         an election under exactly such circumstances.
+       */
       DEBUG(2,("Forcing election on %s %s\n",
               work->work_group,inet_ntoa(d->bcast_ip)));
 
       /* we can attempt to become master browser */
       work->needelection = True;
-  }
-  else
-  {
-     /* local interfaces: force an election */
-    send_election(d, work->work_group, 0, 0, myname);
-
-     /* only removes workgroup completely on a local interface 
-        persistent lmhosts entries on a local interface _will_ be removed).
-      */
-     remove_workgroup(d, work,True);
+    }
+    else
+    {
+      /* we need to force an election, because we are configured
+         not to _become_ the local master, but we still _need_ one,
+         having detected that one doesn't exist.
+       */
+
+      /* local interfaces: force an election */
+      send_election(d, work->work_group, 0, 0, myname);
+
+      /* only removes workgroup completely on a local interface 
+         persistent lmhosts entries on a local interface _will_ be removed).
+       */
+      remove_workgroup(d, work,True);
+      add_workgroup_to_subnet(d, work->work_group);
+    }
   }
 }
 
@@ -199,15 +217,15 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type)
     {
       remove_type_local |= SV_TYPE_MASTER_BROWSER;
     }
-    if (AM_MASTER(work) && strequal(name, lp_workgroup()) && name_type == 0x1d)
+    if (AM_MASTER(work) && strequal(name, myworkgroup) && name_type == 0x1d)
     {
       remove_type_local |= SV_TYPE_MASTER_BROWSER;
     }
-    if (AM_DOMMST(work) && strequal(name, lp_workgroup()) && name_type == 0x1b)
+    if (AM_DOMMST(work) && strequal(name, myworkgroup) && name_type == 0x1b)
     {
       remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
     }
-    if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) && name_type == 0x1c)
+    if (AM_DOMMEM(work) && strequal(name, myworkgroup) && name_type == 0x1c)
     {
       remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
     }
@@ -228,47 +246,48 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type)
 void name_register_work(struct subnet_record *d, char *name, int name_type,
                                int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
 {
-       enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
+  enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
                                  SELF : REGISTER;
 
-       if (source == SELF)
-       {
-               struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
+  if (source == SELF)
+    {
+      struct work_record *work = find_workgroupstruct(d, 
+                                  myworkgroup, False);
 
-               add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
+      add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
 
-               if (work)
-               {
-                       int add_type_local  = False;
-                       int add_type_domain = False;
-                       int add_type_logon  = False;
-
-                       DEBUG(4,("checking next stage: name_register_work %s\n", name));
-
-                       /* work out what to become, from the name type being added */
-
-                       if (ms_browser_name(name, name_type))
-                       {
-                               add_type_local = True;
-                       }
-                       if (strequal(name, lp_workgroup()) && name_type == 0x1d)
-                       {
-                               add_type_local = True;
-                       }
-                       if (strequal(name, lp_workgroup()) && name_type == 0x1b)
-                       {
-                               add_type_domain = True;
-                       }
-                       if (strequal(name, lp_workgroup()) && name_type == 0x1c)
-                       {
-                               add_type_logon = True;
-                       }
-
-                       if (add_type_local ) become_local_master (d, work);
-                       if (add_type_domain) become_domain_master(d, work);
-                       if (add_type_logon ) become_logon_server (d, work);
-               }
-       }
+      if (work)
+      {
+        int add_type_local  = False;
+        int add_type_domain = False;
+        int add_type_logon  = False;
+
+        DEBUG(4,("checking next stage: name_register_work %s\n", name));
+
+        /* work out what to become, from the name type being added */
+
+        if (ms_browser_name(name, name_type))
+        {
+          add_type_local = True;
+        }
+        if (strequal(name, myworkgroup) && name_type == 0x1d)
+        {
+          add_type_local = True;
+        }
+        if (strequal(name, myworkgroup) && name_type == 0x1b)
+        {
+          add_type_domain = True;
+        }
+        if (strequal(name, myworkgroup) && name_type == 0x1c)
+        {
+          add_type_logon = True;
+        }
+
+        if (add_type_local ) become_local_master (d, work);
+        if (add_type_domain) become_domain_master(d, work);
+        if (add_type_logon ) become_logon_server (d, work);
+      }
+    }
 }
 
 
@@ -303,17 +322,18 @@ void become_local_master(struct subnet_record *d, struct work_record *work)
    */
   uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
 
-  if (!work || !d) return;
+  if (!work || !d) 
+    return;
   
   DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
-                                       work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
+           work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
   
   switch (work->mst_state)
   {
     case MST_POTENTIAL: /* while we were nothing but a server... */
     {
       DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
-      work->mst_state = MST_BACK; /* ... an election win was successful */
+      work->mst_state = MST_BACK; /* an election win was successful */
 
       work->ElectionCriterion |= 0x5;
 
@@ -322,7 +342,7 @@ void become_local_master(struct subnet_record *d, struct work_record *work)
       add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
 
       /* add special browser name */
-      add_my_name_entry(d,MSBROWSE        ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
+      add_my_name_entry(d,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP);
 
       /* DON'T do anything else after calling add_my_name_entry() */
       break;
@@ -331,7 +351,7 @@ void become_local_master(struct subnet_record *d, struct work_record *work)
     case MST_BACK: /* while nothing had happened except we won an election... */
     {
       DEBUG(3,("go to second stage: register as master browser\n"));
-      work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */
+      work->mst_state = MST_MSB; /* registering MSBROWSE was successful */
 
       /* add server entry on successful registration of MSBROWSE */
       add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
@@ -346,49 +366,33 @@ void become_local_master(struct subnet_record *d, struct work_record *work)
     case MST_MSB: /* while we were still only registered MSBROWSE state... */
     {
       DEBUG(3,("2nd stage complete: registered as master browser\n"));
-      work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
+      work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
 
       /* update our server status */
       work->ServerType |= SV_TYPE_MASTER_BROWSER;
 
-      DEBUG(3,("become_local_master: updating our server %s to type %x\n", myname, work->ServerType));
+      DEBUG(3,("become_local_master: updating our server %s to type %x\n", 
+                myname, work->ServerType));
 
       add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
 
       if (work->serverlist == NULL) /* no servers! */
       {
         /* ask all servers on our local net to announce to us */
-        /* XXXX OOPS! add_server_entry will always add one entry - our own. */
+        /* XXXX OOPS! add_server_entry always adds one entry - ours. */
         announce_request(work, d->bcast_ip);
       }
 
-      /* If we have WINS support or are a WINS server we must add
-         the workgroup we just became master browser for to the 
-         WINS subnet. This is needed so we have somewhere to save
-         server lists when we do browser synchronization. */
-      if(wins_subnet != 0) 
-        {
-          if(find_workgroupstruct(wins_subnet, work->work_group, True) == 0)
-            DEBUG(0, ("become_local_master: \
-Failed to add workgroup %s to WINS subnet.\n",
-                     work->work_group));
-          else
-            DEBUG(3, ("become_local_master: Added workgroup %s to WINS subnet.\n",
-                   work->work_group));
-
-          /* Reset the announce master timer so that we do an announce as soon as possible
-             now we are a master. */
-          reset_announce_timer();
-        }
+      /* Reset the announce master timer so that we do an announce as soon as possible
+         now we are a master. */
+      reset_announce_timer();
       break;
-
     }
 
     case MST_BROWSER:
     {
       /* don't have to do anything: just report success */
       DEBUG(3,("3rd stage: become master browser!\n"));
-
       break;
     }
   }
@@ -438,7 +442,7 @@ void become_domain_master(struct subnet_record *d, struct work_record *work)
                  work->dom_state = DOMAIN_WAIT;
 
                  /* XXXX the 0x1b is domain master browser name */
-                 add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP);
+                 add_my_name_entry(d, myworkgroup,0x1b,nb_type|NB_ACTIVE|NB_GROUP);
 
                  /* DON'T do anything else after calling add_my_name_entry() */
                  break;
@@ -505,7 +509,7 @@ void become_logon_server(struct subnet_record *d, struct work_record *work)
                  work->log_state = LOGON_WAIT;
 
           /* XXXX the 0x1c is apparently something to do with domain logons */
-          add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP);
+          add_my_name_entry(d, myworkgroup,0x1c,nb_type|NB_ACTIVE|NB_GROUP);
 
                  /* DON'T do anything else after calling add_my_name_entry() */
                  break;
@@ -749,7 +753,7 @@ void process_election(struct packet_struct *p,char *buf)
   
   for (work = d->workgrouplist; work; work = work->next)
     {
-      if (!strequal(work->work_group, lp_workgroup()))
+      if (!strequal(work->work_group, myworkgroup))
        continue;
 
       if (win_election(work, version,criterion,timeup,name)) {
index f2b3ba167aeec4044658584bbbf0e1a6b607b246..27796ec07c4d0da846cf1c43d10b4a9a5d93bcc6 100644 (file)
@@ -263,13 +263,13 @@ struct response_record *queue_netbios_pkt_wins(
   if ((!lp_wins_support()) && (*lp_wins_server()))
     {
       /* samba is not a WINS server, and we are using a WINS server */
-      struct in_addr wins_ip;
-      wins_ip = *interpret_addr2(lp_wins_server());
+      struct in_addr real_wins_ip;
+      real_wins_ip = *interpret_addr2(lp_wins_server());
 
-      if (!zero_ip(wins_ip))
+      if (!zero_ip(real_wins_ip))
        {
          bcast = False;
-         send_ip = wins_ip;
+         send_ip = real_wins_ip;
        }
       else
        {
index 022b5521a21dac20bb6461a9ee25d6ed6551797c..91636428961327b884d0afafa74e62f5a5bce1fc 100644 (file)
@@ -37,6 +37,7 @@ extern int DEBUGLEVEL;
 
 extern pstring scope;
 extern pstring myname;
+extern fstring myworkgroup;
 extern struct in_addr ipzero;
 extern struct in_addr wins_ip;
 
@@ -141,6 +142,9 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
     }
     else
     {
+      DEBUG(4,("add_my_name_entry registering name %s with WINS server.\n",
+                name));
+      
       /* a time-to-live allows us to refresh this name with the WINS server. */
          queue_netbios_pkt_wins(ClientNMB,
                                 re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
@@ -179,33 +183,32 @@ void add_domain_names(time_t t)
 
   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
   {
-    work = find_workgroupstruct(d, lp_workgroup(), False);
+    work = find_workgroupstruct(d, myworkgroup, False);
     if (lp_domain_logons() && work && work->log_state == LOGON_NONE)
     {
-      make_nmb_name(&n,lp_workgroup(),0x1c,scope);
+      make_nmb_name(&n,myworkgroup,0x1c,scope);
       if (!find_name(d->namelist, &n, FIND_SELF))
       {
         /* logon servers are group names - we don't expect this to fail. */
         DEBUG(0,("%s attempting to become logon server for %s %s\n",
-             timestring(), lp_workgroup(), inet_ntoa(d->bcast_ip)));
+             timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
         become_logon_server(d, work);
       }
     }
   }
 
-  if(wins_subnet != 0)
-    work = find_workgroupstruct(wins_subnet, lp_workgroup(), False);
-
-  if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE)
-    {
-
-      DEBUG(0,("add_domain_names:Checking for domain master on workgroup %s\n", lp_workgroup()));
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
+ { 
+   work = find_workgroupstruct(d, myworkgroup, True);
 
-      make_nmb_name(&n,lp_workgroup(),0x1b,scope);
-      if (!find_name(wins_subnet->namelist, &n, FIND_SELF))
+   if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE)
+     {
+      make_nmb_name(&n,myworkgroup,0x1b,scope);
+      if (!find_name(d->namelist, &n, FIND_SELF))
       {
-        DEBUG(0,("add_domain_names: attempting to become domain master browser on workgroup %s\n",
-                  lp_workgroup()));
+        DEBUG(0,("%s add_domain_names: attempting to become domain master \
+browser on workgroup %s %s\n",
+                  timestring(), myworkgroup, inet_ntoa(d->bcast_ip)));
 
         if (lp_wins_support())
         {
@@ -216,8 +219,8 @@ void add_domain_names(time_t t)
            */
                
           DEBUG(1,("%s initiating becoming domain master for %s\n",
-                       timestring(), lp_workgroup()));
-          become_domain_master(wins_subnet, work);
+                       timestring(), myworkgroup));
+          become_domain_master(d, work);
         }
         else
         {
@@ -228,15 +231,17 @@ void add_domain_names(time_t t)
              NetBIOS name 0x1b.
            */
 
-          DEBUG(0,("add_domain_names:querying WINS for domain master on workgroup %s\n", lp_workgroup()));
+          DEBUG(0,("add_domain_names:querying WINS for domain master \
+on workgroup %s\n", myworkgroup));
 
           queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,NAME_QUERY_DOMAIN,
-                               lp_workgroup(), 0x1b,
+                               myworkgroup, 0x1b,
                                0, 0,0,NULL,NULL,
                                False, False, ipzero, ipzero);
         }
       }
     }
+  }
 }
 
 
@@ -255,7 +260,6 @@ void add_my_names(void)
   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
   {
     BOOL wins = (lp_wins_support() && (d == wins_subnet));
-    struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
 
     add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE);
     add_my_name_entry(d, myname,0x03,nb_type|NB_ACTIVE);
index e1738007df1b6caeea3fcdfe7be257861a966ea2..00e940df671e9ca3502c3cfbe70937b7c8b08cff 100644 (file)
@@ -528,7 +528,8 @@ void reply_name_query(struct packet_struct *p)
     }
   }
 
-  DEBUG(3,("Name query "));
+  DEBUG(3,("Name query from %s for name %s<0x%x>\n", 
+                  inet_ntoa(p->ip), question->name, question->name_type));
   
   if (search == 0)
   {
index 218a7a349ef317b066a020bcc07b557d7d7f9099..23d48d9ced7c45523be2f372907b945bdf733505 100644 (file)
@@ -37,6 +37,7 @@ extern pstring scope;
 extern BOOL CanRecurse;
 
 extern pstring myname;
+extern fstring myworkgroup;
 
 extern int ClientNMB;
 extern int ClientDGRAM;
@@ -603,7 +604,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf)
          struct work_record *work;
          for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
        }
-      add_my_subnets(lp_workgroup());
+      add_my_subnets(myworkgroup);
     }
   
   /* stop browsing altogether. i don't think this is a good idea! */
@@ -639,7 +640,7 @@ static void process_announce_request(struct packet_struct *p,char *buf)
      this workgroup before announcing, particularly as we only
      respond on local interfaces anyway.
 
-     if (strequal(dgram->dest_name, lp_workgroup()) return; ???
+     if (strequal(dgram->dest_name, myworkgroup) return; ???
    */
 
   if (!d) 
index 550f3198f7cca9da093f4c40ac14d59d5a7d0fbb..11f005b78521fcbc88bfc3e0d09e9ff3d5cbf68f 100644 (file)
@@ -40,6 +40,7 @@ int ClientDGRAM = -1;
 extern pstring myhostname;
 static pstring host_file;
 extern pstring myname;
+extern fstring myworkgroup;
 
 /* are we running as a daemon ? */
 static BOOL is_daemon = False;
@@ -67,7 +68,7 @@ static int sig_term()
   
   /* announce all server entries as 0 time-to-live, 0 type */
   /* XXXX don't care if we never receive a response back... yet */
-  remove_my_servers();
+  announce_my_servers_removed();
 
   /* XXXX other things: if we are a master browser, force an election? */
   
@@ -203,9 +204,6 @@ BOOL reload_services(BOOL test)
     reload_services(True);
   }
 
-  load_interfaces();
-  add_subnet_interfaces();
-
   /* Do a sanity check for a misconfigured nmbd */
   if(lp_wins_support() && *lp_wins_server()) {
     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
@@ -502,6 +500,8 @@ static void usage(char *pname)
 
   reload_services(True);
 
+  strcpy(myworkgroup, lp_workgroup());
+
   set_samba_nb_type();
 
   if (!is_daemon && !is_a_socket(0)) {
@@ -549,15 +549,16 @@ static void usage(char *pname)
     DEBUG(3,("Loaded hosts file\n"));
   }
 
+  load_interfaces();
+  add_my_subnets(myworkgroup);
+
   add_my_names();
 
-  if (strequal(lp_workgroup(),"*")) {
+  if (strequal(myworkgroup,"*")) {
     DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
     exit(1);
   }
 
-  add_my_subnets(lp_workgroup());
-
   DEBUG(3,("Checked names\n"));
   
   load_netbios_names();
index 40611e4c3a3798fe75002b37fcd50e3e878c43c5..af0b05bb5d87453cb221bcb6e8b02cdb67ed0674 100644 (file)
@@ -152,8 +152,11 @@ typedef struct
   int os_level;
   int max_ttl;
   int ReadSize;
+  int shmem_size;
+  int shmem_hash_size;
   BOOL bWINSsupport;
   BOOL bWINSproxy;
+  BOOL bLocalMaster;
   BOOL bPreferredMaster;
   BOOL bDomainMaster;
   BOOL bDomainLogons;
@@ -427,6 +430,8 @@ struct parm_struct
   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL},
   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL},
   {"read size",        P_INTEGER, P_GLOBAL, &Globals.ReadSize,          NULL},
+  {"shared mem size",  P_INTEGER, P_GLOBAL, &Globals.shmem_size,        NULL},
+  {"shared file entries",  P_INTEGER, P_GLOBAL, &Globals.shmem_hash_size, NULL},
 #ifdef KANJI
   {"coding system",    P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
 #endif /* KANJI */
@@ -437,6 +442,7 @@ struct parm_struct
   {"wins server",      P_STRING,  P_GLOBAL, &Globals.szWINSserver,      NULL},
   {"preferred master", P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
   {"prefered master",  P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
+  {"local master",     P_BOOL,    P_GLOBAL, &Globals.bLocalMaster,      NULL},
   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL},
   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL},
   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL},
@@ -601,15 +607,11 @@ static void init_globals(void)
   Globals.bSyslogOnly = False;
   Globals.os_level = 0;
   Globals.max_ttl = 60*60*4; /* 2 hours default */
-  Globals.bPreferredMaster = True;
-  Globals.bDomainMaster = False;
-  Globals.bDomainLogons = False;
-  Globals.bBrowseList = True;
-  Globals.bWINSsupport = False;
-  Globals.bWINSproxy = False;
   Globals.ReadSize = 16*1024;
+  Globals.shmem_size = SHMEM_SIZE;
+  Globals.shmem_hash_size = SHMEM_HASH_SIZE;
   Globals.bUnixRealname = False;
-#ifdef NETGROUP
+#if (defined(NETGROUP) && defined(AUTOMOUNT))
   Globals.bNISHomeMap = False;
   string_set(&Globals.szNISHomeMapName, "auto.home");
 #endif
@@ -617,6 +619,25 @@ static void init_globals(void)
   coding_system = interpret_coding_system (KANJI, SJIS_CODE);
 #endif /* KANJI */
 
+/* these parameters are set to defaults that are more appropriate
+   for the increasing samba install base:
+
+   as a member of the workgroup, that will possibly become a
+   _local_ master browser (lm = True).  this is opposed to a forced
+   local master browser startup (pm = True).
+
+   doesn't provide WINS server service by default (wsupp = False),
+   and doesn't provide domain master browser services by default, either.
+
+*/
+
+  Globals.bPreferredMaster = False;
+  Globals.bLocalMaster = True;
+  Globals.bDomainMaster = False;
+  Globals.bDomainLogons = False;
+  Globals.bBrowseList = True;
+  Globals.bWINSsupport = False;
+  Globals.bWINSproxy = False;
 }
 
 /***************************************************************************
@@ -771,6 +792,7 @@ FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName)
 
 FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
 FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
+FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster)
 FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
 FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
 FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
@@ -799,6 +821,8 @@ FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
 FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize)
+FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size)
+FN_GLOBAL_INTEGER(lp_shmem_hash_size,&Globals.shmem_hash_size)
 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
index 2437b8b17e8dd2f6165f45b72d0bebe7ccf2f0f6..bc099dd1e8f3c95246448c7df963696371fa2d72 100644 (file)
@@ -433,6 +433,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
   BOOL isrootdir;
   pstring filename;
   BOOL matched;
+  BOOL needslash;
 
   *path = *pathreal = *filename = 0;
 
@@ -440,6 +441,9 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
               strequal(Connections[cnum].dirpath,".") ||
               strequal(Connections[cnum].dirpath,"/"));
   
+  needslash = 
+        ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
+
   if (!Connections[cnum].dirptr)
     return(False);
   
@@ -467,7 +471,8 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo
          strcpy(fname,filename);
          *path = 0;
          strcpy(path,Connections[cnum].dirpath);
-         strcat(path,"/");
+          if(needslash)
+           strcat(path,"/");
          strcpy(pathreal,path);
          strcat(path,fname);
          strcat(pathreal,dname);
index 1f1ac8600a06208ad4cf93ef2bf104723e529e6c..8b9fb485ae04a9b8768a9423c3905a307927779a 100644 (file)
@@ -37,6 +37,7 @@ extern files_struct Files[];
 extern connection_struct Connections[];
 
 extern fstring local_machine;
+extern fstring myworkgroup;
 
 #define NERR_Success 0
 #define NERR_badpass 86
@@ -812,7 +813,7 @@ static int get_server_info(uint32 servertype,
     if (!next_token(&ptr,s->comment, NULL)) continue;
     if (!next_token(&ptr,s->domain , NULL)) {
       /* this allows us to cope with an old nmbd */
-      strcpy(s->domain,lp_workgroup()); 
+      strcpy(s->domain,myworkgroup); 
     }
     
     if (sscanf(stype,"%X",&s->type) != 1) { 
@@ -982,7 +983,7 @@ static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data,
   if (strcmp(str1, "WrLehDz") == 0) {
     StrnCpy(domain, p, sizeof(fstring)-1);
   } else {
-    StrnCpy(domain, lp_workgroup(), sizeof(fstring)-1);    
+    StrnCpy(domain, myworkgroup, sizeof(fstring)-1);    
   }
 
   if (lp_browse_list())
@@ -1668,7 +1669,7 @@ static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data,
 
       strcpy(comment,lp_serverstring());
 
-      if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) {
+      if ((count=get_server_info(SV_TYPE_ALL,&servers,myworkgroup))>0) {
        for (i=0;i<count;i++)
          if (strequal(servers[i].name,local_machine))
       {
@@ -1754,7 +1755,7 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
   p += 4;
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */
-  strcpy(p2,lp_workgroup());
+  strcpy(p2,myworkgroup);
   strupper(p2);
   p2 = skip_string(p2,1);
   p += 4;
@@ -1764,7 +1765,7 @@ static BOOL api_NetWkstaGetInfo(int cnum,uint16 vuid, char *param,char *data,
   p += 2;
 
   SIVAL(p,0,PTR_DIFF(p2,*rdata));
-  strcpy(p2,lp_workgroup());   /* don't know.  login domain?? */
+  strcpy(p2,myworkgroup);      /* don't know.  login domain?? */
   p2 = skip_string(p2,1);
   p += 4;
 
@@ -2228,7 +2229,7 @@ static BOOL api_WWkstaUserLogon(int cnum,uint16 vuid, char *param,char *data,
       strupper(mypath);
       PACKS(&desc,"z",mypath); /* computer */
     }
-    PACKS(&desc,"z",lp_workgroup());/* domain */
+    PACKS(&desc,"z",myworkgroup);/* domain */
     PACKS(&desc,"z",lp_logon_script());                /* script path */
     PACKI(&desc,"D",0x00000000);               /* reserved */
   }
index 634d7af7f42b82c68c5229ece52333d73f93012d..a294ee4f4914c5c5b7b77cc9e75e007d1064b8ef 100644 (file)
@@ -42,6 +42,7 @@ extern files_struct Files[];
 extern BOOL case_sensitive;
 extern pstring sesssetup_user;
 extern int Client;
+extern fstring myworkgroup;
 
 /* this macro should always be used to extract an fnum (smb_fid) from
 a packet to ensure chaining works correctly */
@@ -250,7 +251,7 @@ static void LsarpcTNP3(char *data,char **rdata, int *rdata_len)
 {
   uint32 dword1;
   uint16 word1;
-  char * workgroup = lp_workgroup();
+  char * workgroup = myworkgroup;
   int wglen = strlen(workgroup);
   int i;
 
index bb75211deb5185e5c72a30cda229e6822d9139ff..639c386c2fac7a0d131ae2c9399e748e6ee5874c 100644 (file)
@@ -40,6 +40,7 @@ extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
 extern pstring sesssetup_user;
+extern fstring myworkgroup;
 extern int Client;
 
 /* this macro should always be used to extract an fnum (smb_fid) from
@@ -480,7 +481,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     p = smb_buf(outbuf);
     strcpy(p,"Unix"); p = skip_string(p,1);
     strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
-    strcpy(p,lp_workgroup()); p = skip_string(p,1);
+    strcpy(p,myworkgroup); p = skip_string(p,1);
     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
     /* perhaps grab OS version here?? */
   }
index 0f72efc4788fa6a2fc1115f77e3617459c58ad8c..fe0868b34ac4b0da087b57a1ce28f15d1ffe1c21 100644 (file)
@@ -25,6 +25,7 @@
 pstring servicesf = CONFIGFILE;
 extern pstring debugf;
 extern pstring sesssetup_user;
+extern fstring myworkgroup;
 
 char *InBuffer = NULL;
 char *OutBuffer = NULL;
@@ -33,8 +34,6 @@ char *last_inbuf = NULL;
 int am_parent = 1;
 int atexit_set = 0;
 
-BOOL share_mode_pending = False;
-
 /* the last message the was processed */
 int last_message = -1;
 
@@ -113,6 +112,7 @@ static int find_free_connection(int hash);
 void  *dflt_sig(void)
 {
   exit_server("caught signal");
+  return 0; /* Keep -Wall happy :-) */
 }
 /****************************************************************************
   Send a SIGTERM to our process group.
@@ -837,8 +837,8 @@ file_fd_struct *fd_get_already_open(struct stat *sbuf)
   for(i = 0; i <= max_file_fd_used; i++) {
     fd_ptr = &FileFd[i];
     if((fd_ptr->ref_count > 0) &&
-       (((int32)sbuf->st_dev) == fd_ptr->dev) &&
-       (((int32)sbuf->st_ino) == fd_ptr->inode)) {
+       (((uint32)sbuf->st_dev) == fd_ptr->dev) &&
+       (((uint32)sbuf->st_ino) == fd_ptr->inode)) {
       fd_ptr->ref_count++;
       DEBUG(3,
        ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n",
@@ -861,8 +861,8 @@ file_fd_struct *fd_get_new()
   for(i = 0; i < MAX_OPEN_FILES; i++) {
     fd_ptr = &FileFd[i];
     if(fd_ptr->ref_count == 0) {
-      fd_ptr->dev = (int32)-1;
-      fd_ptr->inode = (int32)-1;
+      fd_ptr->dev = (uint32)-1;
+      fd_ptr->inode = (uint32)-1;
       fd_ptr->fd = -1;
       fd_ptr->fd_readonly = -1;
       fd_ptr->fd_writeonly = -1;
@@ -927,8 +927,8 @@ int fd_attempt_close(file_fd_struct *fd_ptr)
       fd_ptr->fd_readonly = -1;
       fd_ptr->fd_writeonly = -1;
       fd_ptr->real_open_flags = -1;
-      fd_ptr->dev = -1;
-      fd_ptr->inode = -1;
+      fd_ptr->dev = (uint32)-1;
+      fd_ptr->inode = (uint32)-1;
     }
   } 
  return fd_ptr->ref_count;
@@ -1124,8 +1124,8 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *s
         sbuf = &statbuf;
       }
       /* Set the correct entries in fd_ptr. */
-      fd_ptr->dev = (int32)sbuf->st_dev;
-      fd_ptr->inode = (int32)sbuf->st_ino;
+      fd_ptr->dev = (uint32)sbuf->st_dev;
+      fd_ptr->inode = (uint32)sbuf->st_ino;
 
       Files[fnum].fd_ptr = fd_ptr;
       Connections[cnum].num_files_open++;
@@ -1141,7 +1141,6 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *s
       Files[fnum].can_read = ((flags & O_WRONLY)==0);
       Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0);
       Files[fnum].share_mode = 0;
-      Files[fnum].share_pending = False;
       Files[fnum].print_file = Connections[cnum].printer;
       Files[fnum].modified = False;
       Files[fnum].cnum = cnum;
@@ -1241,38 +1240,49 @@ close a file - possibly invalidating the read prediction
 ****************************************************************************/
 void close_file(int fnum)
 {
-  int cnum = Files[fnum].cnum;
-  invalidate_read_prediction(Files[fnum].fd_ptr->fd);
-  Files[fnum].open = False;
+  files_struct *fs_p = &Files[fnum];
+  int cnum = fs_p->cnum;
+  uint32 dev = fs_p->fd_ptr->dev;
+  uint32 inode = fs_p->fd_ptr->inode;
+  share_lock_token token;
+
+  invalidate_read_prediction(fs_p->fd_ptr->fd);
+  fs_p->open = False;
   Connections[cnum].num_files_open--;
-  if(Files[fnum].wbmpx_ptr) 
+  if(fs_p->wbmpx_ptr) 
     {
-      free((char *)Files[fnum].wbmpx_ptr);
-      Files[fnum].wbmpx_ptr = NULL;
+      free((char *)fs_p->wbmpx_ptr);
+      fs_p->wbmpx_ptr = NULL;
     }
 
 #if USE_MMAP
-  if(Files[fnum].mmap_ptr) 
+  if(fs_p->mmap_ptr) 
     {
-      munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size);
-      Files[fnum].mmap_ptr = NULL;
+      munmap(fs_p->mmap_ptr,fs_p->mmap_size);
+      fs_p->mmap_ptr = NULL;
     }
 #endif
 
   if (lp_share_modes(SNUM(cnum)))
-    del_share_mode(fnum);
+  {
+    lock_share_entry( cnum, dev, inode, &token);
+    del_share_mode(token, fnum);
+  }
+
+  fd_attempt_close(fs_p->fd_ptr);
 
-  fd_attempt_close(Files[fnum].fd_ptr);
+  if (lp_share_modes(SNUM(cnum)))
+    unlock_share_entry( cnum, dev, inode, token);
 
   /* NT uses smbclose to start a print - weird */
-  if (Files[fnum].print_file)
+  if (fs_p->print_file)
     print_file(fnum);
 
   /* check for magic scripts */
   check_magic(fnum,cnum);
 
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
-          timestring(),Connections[cnum].user,Files[fnum].name,
+          timestring(),Connections[cnum].user,fs_p->name,
           Connections[cnum].num_files_open));
 }
 
@@ -1334,17 +1344,44 @@ return True if sharing doesn't prevent the operation
 ********************************************************************/
 BOOL check_file_sharing(int cnum,char *fname)
 {
-  int pid=0;
-  int share_mode = get_share_mode_byname(cnum,fname,&pid);
+  int i;
+  int ret = False;
+  min_share_mode_entry *old_shares = 0;
+  int num_share_modes;
+  struct stat sbuf;
+  share_lock_token token;
+  int pid = getpid();
 
-  if (!pid || !share_mode) return(True);
-  if (share_mode == DENY_DOS)
-    return(pid == getpid());
+  if(!lp_share_modes(SNUM(cnum)))
+    return True;
+
+  if (stat(fname,&sbuf) == -1) return(True);
+
+  lock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &token);
+  num_share_modes = get_share_modes(cnum, token, 
+                     (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &old_shares);
+
+  for( i = 0; i < num_share_modes; i++)
+  {
+    if (old_shares[i].share_mode != DENY_DOS)
+      goto free_and_exit;
+
+    if(old_shares[i].pid != pid);
+      goto free_and_exit;
+  }
 
   /* XXXX exactly what share mode combinations should be allowed for
      deleting/renaming? */
-  return(False);
+  /* If we got here then either there were no share modes or
+     all share modes were DENY_DOS and the pid == getpid() */
+  ret = True;
+
+free_and_exit:
+
+  unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token);
+  if(old_shares != NULL)
+    free((char *)old_shares);
+  return(ret);
 }
 
 /****************************************************************************
@@ -1373,25 +1410,31 @@ open a file with a share mode
 void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
                      int mode,int *Access,int *action)
 {
+  files_struct *fs_p = &Files[fnum];
   int flags=0;
   int flags2=0;
   int deny_mode = (share_mode>>4)&7;
   struct stat sbuf;
   BOOL file_existed = file_exist(fname,&sbuf);
+  BOOL share_locked = False;
   BOOL fcbopen = False;
-  int share_pid=0;
+  share_lock_token token;
+  uint32 dev = 0;
+  uint32 inode = 0;
 
-  Files[fnum].open = False;
-  Files[fnum].fd_ptr = 0;
+  fs_p->open = False;
+  fs_p->fd_ptr = 0;
 
   /* this is for OS/2 EAs - try and say we don't support them */
-  if (strstr(fname,".+,;=[].")) {
+  if (strstr(fname,".+,;=[].")) 
+  {
     unix_ERR_class = ERRDOS;
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
     return;
   }
 
-  if ((ofun & 0x3) == 0 && file_existed) {
+  if ((ofun & 0x3) == 0 && file_existed)  
+  {
     errno = EEXIST;
     return;
   }
@@ -1405,7 +1448,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
      append does not mean the same thing under dos and unix */
 
   switch (share_mode&0xF)
-    {
+  {
     case 1: 
       flags = O_WRONLY; 
       break;
@@ -1419,18 +1462,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
     default:
       flags = O_RDONLY;
       break;
-    }
+  }
   
   if (flags != O_RDONLY && file_existed && 
-      (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) {
-    if (!fcbopen) {
+      (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) 
+  {
+    if (!fcbopen) 
+    {
       errno = EACCES;
       return;
     }
     flags = O_RDONLY;
   }
 
-  if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) {
+  if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) 
+  {
     DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname));
     errno = EINVAL;
     return;
@@ -1438,21 +1484,36 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
   if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
 
-  if (lp_share_modes(SNUM(cnum))) {
-    int old_share=0;
+  if (lp_share_modes(SNUM(cnum))) 
+  {
+    int num_shares = 0;
+    int i;
+    min_share_mode_entry *old_shares = 0;
+
 
     if (file_existed)
-      old_share = get_share_mode(cnum,&sbuf,&share_pid);
+    {
+      dev = (uint32)sbuf.st_dev;
+      inode = (uint32)sbuf.st_ino;
+      lock_share_entry(cnum, dev, inode, &token);
+      share_locked = True;
+      num_shares = get_share_modes(cnum, token, dev, inode, &old_shares);
+    }
 
-    if (share_pid) {
+    for(i = 0; i < num_shares; i++)
+    {
       /* someone else has a share lock on it, check to see 
         if we can too */
-      int old_open_mode = old_share&0xF;
-      int old_deny_mode = (old_share>>4)&7;
+      int old_open_mode = old_shares[i].share_mode &0xF;
+      int old_deny_mode = (old_shares[i].share_mode >>4)&7;
 
-      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) {
+      if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) 
+      {
        DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n",
                 deny_mode,old_deny_mode,old_open_mode,fname));
+        free((char *)old_shares);
+        if(share_locked)
+          unlock_share_entry(cnum, dev, inode, token);
        errno = EACCES;
        unix_ERR_class = ERRDOS;
        unix_ERR_code = ERRbadshare;
@@ -1461,21 +1522,25 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
 
       {
        int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
-                                         share_pid,fname);
+                                         old_shares[i].pid,fname);
 
        if ((access_allowed == AFAIL) ||
            (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) ||
            (access_allowed == AREAD && flags == O_WRONLY) ||
-           (access_allowed == AWRITE && flags == O_RDONLY)) {
+           (access_allowed == AWRITE && flags == O_RDONLY)) 
+        {
          DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n",
                   deny_mode,old_deny_mode,old_open_mode,
-                  share_pid,fname,
+                  old_shares[i].pid,fname,
                   access_allowed));
+          free((char *)old_shares);
+          if(share_locked)
+            unlock_share_entry(cnum, dev, inode, token);
          errno = EACCES;
          unix_ERR_class = ERRDOS;
          unix_ERR_code = ERRbadshare;
          return;
-       }
+        }
        
        if (access_allowed == AREAD)
          flags = O_RDONLY;
@@ -1484,76 +1549,69 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
          flags = O_WRONLY;
       }
     }
+    if(old_shares != 0)
+      free((char *)old_shares);
   }
 
   DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n",
           flags,flags2,mode));
 
   open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0);
-  if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) {
+  if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen) 
+  {
     flags = O_RDONLY;
     open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 );
   }
 
-  if (Files[fnum].open) {
+  if (fs_p->open) 
+  {
     int open_mode=0;
-    switch (flags) {
-    case O_RDONLY:
-      open_mode = 0;
-      break;
-    case O_RDWR:
-      open_mode = 2;
-      break;
-    case O_WRONLY:
-      open_mode = 1;
-      break;
+
+    if((share_locked == False) && lp_share_modes(SNUM(cnum)))
+    {
+      /* We created the file - thus we must now lock the share entry before creating it. */
+      dev = fs_p->fd_ptr->dev;
+      inode = fs_p->fd_ptr->inode;
+      lock_share_entry(cnum, dev, inode, &token);
+      share_locked = True;
     }
 
-    Files[fnum].share_mode = (deny_mode<<4) | open_mode;
-    Files[fnum].share_pending = True;
+    switch (flags) 
+    {
+      case O_RDONLY:
+        open_mode = 0;
+        break;
+      case O_RDWR:
+        open_mode = 2;
+        break;
+      case O_WRONLY:
+        open_mode = 1;
+        break;
+    }
+
+    fs_p->share_mode = (deny_mode<<4) | open_mode;
 
-    if (Access) {
+    if (Access)
       (*Access) = open_mode;
-    }
-    
-    if (action) {
+
+    if (action) 
+    {
       if (file_existed && !(flags2 & O_TRUNC)) *action = 1;
       if (!file_existed) *action = 2;
       if (file_existed && (flags2 & O_TRUNC)) *action = 3;
     }
 
-    if (!share_pid)
-      share_mode_pending = True;
-
     if ((flags2&O_TRUNC) && file_existed)
       truncate_unless_locked(fnum,cnum);
-  }
-}
-
 
+    if (lp_share_modes(SNUM(cnum)))
+      set_share_mode(token, fnum);
+  }
 
-/*******************************************************************
-check for files that we should now set our share modes on
-********************************************************************/
-static void check_share_modes(void)
-{
-  int i;
-  for (i=0;i<MAX_OPEN_FILES;i++)
-    if(Files[i].open && Files[i].share_pending) {
-      if (lp_share_modes(SNUM(Files[i].cnum))) {
-       int pid=0;
-       get_share_mode_by_fnum(Files[i].cnum,i,&pid);
-       if (!pid) {
-         set_share_mode(i,Files[i].share_mode);
-         Files[i].share_pending = False;
-       }
-      } else {
-       Files[i].share_pending = False; 
-      }
-    }
+  if (share_locked && lp_share_modes(SNUM(cnum)))
+    unlock_share_entry( cnum, dev, inode, token);
 }
 
-
 /****************************************************************************
 seek a file. Try to avoid the seek if possible
 ****************************************************************************/
@@ -2694,18 +2752,18 @@ int reply_nt1(char *outbuf)
    */
   encrypt_len = doencrypt?challenge_len:0;
 #if UNICODE
-  data_len = encrypt_len + 2*(strlen(lp_workgroup())+1);
+  data_len = encrypt_len + 2*(strlen(myworkgroup)+1);
 #else
-  data_len = encrypt_len + strlen(lp_workgroup()) + 1;
+  data_len = encrypt_len + strlen(myworkgroup) + 1;
 #endif
 
   set_message(outbuf,17,data_len,True);
 
 #if UNICODE
   /* put the OEM'd domain name */
-  PutUniCode(smb_buf(outbuf)+encrypt_len,lp_workgroup());
+  PutUniCode(smb_buf(outbuf)+encrypt_len,myworkgroup);
 #else
-  strcpy(smb_buf(outbuf)+encrypt_len, lp_workgroup());
+  strcpy(smb_buf(outbuf)+encrypt_len, myworkgroup);
 #endif
 
   CVAL(outbuf,smb_vwv1) = secword;
@@ -3258,9 +3316,9 @@ void exit_server(char *reason)
 #endif
   }    
 
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
   stop_share_mode_mgmt();
-#endif
+#endif /* FAST_SHARE_MODES */
 
   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
   exit(0);
@@ -3738,24 +3796,6 @@ static void process(void)
       if (lp_readprediction())
        do_read_prediction();
 
-      {
-       extern pstring share_del_pending;
-       if (*share_del_pending) {
-         unbecome_user();
-         if (!unlink(share_del_pending))
-           DEBUG(3,("Share file deleted %s\n",share_del_pending));
-         else
-           DEBUG(2,("Share del failed of %s\n",share_del_pending));
-         share_del_pending[0] = 0;
-       }
-      }
-
-      if (share_mode_pending) {
-       unbecome_user();
-       check_share_modes();
-       share_mode_pending=False;
-      }
-
       errno = 0;      
 
       for (counter=SMBD_SELECT_LOOP; 
@@ -3787,6 +3827,7 @@ static void process(void)
          if (!(counter%SMBD_RELOAD_CHECK))
            reload_services(True);
 
+#if 0 /* JRA */
          /* check the share modes every 10 secs */
          if (!(counter%SHARE_MODES_CHECK))
            check_share_modes();
@@ -3794,6 +3835,7 @@ static void process(void)
          /* clean the share modes every 5 minutes */
          if (!(counter%SHARE_MODES_CLEAN))
            clean_share_modes();
+#endif /* JRA */
 
          /* automatic timeout if all connections are closed */      
          if (num_connections_open==0 && counter >= IDLE_CLOSED_TIMEOUT) {
@@ -4082,6 +4124,8 @@ static void usage(char *pname)
   if (!reload_services(False))
     return(-1);        
 
+  strcpy(myworkgroup, lp_workgroup());
+
 #ifndef NO_SIGNAL_TEST
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
@@ -4128,10 +4172,10 @@ static void usage(char *pname)
   if (!open_sockets(is_daemon,port))
     exit(1);
 
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
   if (!start_share_mode_mgmt())
     exit(1);
-#endif
+#endif /* FAST_SHARE_MODES */
 
   /* possibly reload the services file. */
   reload_services(True);
index 38c7031b665b593c5d05a06f2e6ccbbbe6c7cadc..1d9977c66e0e557e7eda56de217f4e1c5b2a4bca 100644 (file)
@@ -277,6 +277,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
                    strequal(Connections[cnum].dirpath,"/"));
   BOOL was_8_3;
   int nt_extmode; /* Used for NT connections instead of mode */
+  BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
 
   *fname = 0;
   *out_of_space = False;
@@ -323,7 +324,8 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l
            continue;
 
          strcpy(pathreal,Connections[cnum].dirpath);
-         strcat(pathreal,"/");
+          if(needslash)
+           strcat(pathreal,"/");
          strcat(pathreal,fname);
          if (sys_stat(pathreal,&sbuf) != 0) 
            {
index e8e57b3dd7cee73210d382dfffa3e4dec69a945d..b439741e6c6a57239736e159d6e6b5a0fb9d4dea 100644 (file)
@@ -53,6 +53,81 @@ int            Ucrit_pid[100];  /* Ugly !!! */        /* added by OH */
 int            Ucrit_MaxPid=0;                        /* added by OH */
 unsigned int   Ucrit_IsActive = 0;                    /* added by OH */
 
+#ifndef FAST_SHARE_MODES
+static char *read_share_file(int fd, char *fname, char *progname)
+{
+  struct stat sb;
+  char *buf;
+  int size;
+
+  if(fstat(fd, &sb) != 0)
+  {
+    printf("%s: ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
+                  progname, fname, strerror(errno));
+    return 0;
+  }
+
+  if(sb.st_size == 0)
+  {
+     return 0;
+  }
+
+  /* Allocate space for the file */
+  if((buf = (char *)malloc(sb.st_size)) == NULL)
+  {
+    printf("%s: read_share_file: malloc for file size %d fail !\n", 
+              progname, (int)sb.st_size);
+    return 0;
+  }
+
+  if(lseek(fd, 0, SEEK_SET) != 0)
+  {
+    printf("%s: ERROR: read_share_file: Failed to reset position to 0 \
+for share file %s (%s)\n", progname, fname, strerror(errno));
+    if(buf)
+      free(buf);
+    return 0;
+  }
+
+  if (read(fd,buf,sb.st_size) != sb.st_size)
+  {
+    printf("%s: ERROR: read_share_file: Failed to read share file %s (%s)\n",
+               progname, fname, strerror(errno));
+    if(buf)
+      free(buf);
+    return 0;
+  }
+
+  if (IVAL(buf,0) != LOCKING_VERSION) {
+    printf("%s: ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, 
+              progname, IVAL(buf,0), LOCKING_VERSION);
+    if(buf)
+      free(buf);
+    return 0;
+  }
+
+  /* Sanity check for file contents */
+  size = sb.st_size;
+  size -= 10; /* Remove the header */
+
+  /* Remove the filename component. */
+  size -= SVAL(buf, 8);
+
+  /* The remaining size must be a multiple of 16 - error if not. */
+  if((size % 16) != 0)
+  {
+    printf("%s: ERROR: read_share_file: share file %s is an incorrect length.\n", 
+             progname, fname);
+    if(buf)
+      free(buf);
+    return 0;
+  }
+
+  return buf;
+}
+#endif /* FAST_SHARE_MODES */
+
  int main(int argc, char *argv[])
 {
   FILE *f;
@@ -64,16 +139,16 @@ unsigned int   Ucrit_IsActive = 0;                    /* added by OH */
   BOOL firstopen=True;
   BOOL processes_only=False;
   int last_pid=0;
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
   pstring shmem_file_name;
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
+  share_mode_record *file_scanner_p;
+  smb_shm_offset_t *mode_array;
   int bytes_free, bytes_used, bytes_overhead, bytes_total;
-#else
-  int n;
+#else /* FAST_SHARE_MODES */
   void *dir;
   char *s;
-#endif
+#endif /* FAST_SHARE_MODES */
+  int i;
   struct session_record *ptr;
 
 
@@ -226,101 +301,110 @@ unsigned int   Ucrit_IsActive = 0;                    /* added by OH */
 
   printf("\n");
 
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES 
   /*******************************************************************
   initialize the shared memory for share_mode management 
   ******************************************************************/
-
    
   strcpy(shmem_file_name,lp_lockdir());
   trim_string(shmem_file_name,"","/");
   if (!*shmem_file_name) exit(-1);
   strcat(shmem_file_name, "/SHARE_MEM_FILE");
-  if(!smb_shm_open(shmem_file_name, SHMEM_SIZE)) exit(-1);
+  if(!smb_shm_open(shmem_file_name, lp_shmem_size())) exit(-1);
   
-  if(!smb_shm_lock())
+  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+  if(mode_array == NULL)
   {
-     smb_shm_close();
-     exit (-1);
+    printf("%s: base of shared memory hash array == 0! Exiting.\n", argv[0]);
+    smb_shm_close();
+    exit(-1);
   }
 
-  scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
+  for( i = 0; i < lp_shmem_hash_size(); i++)
   {
-     int pid,mode;
-     struct timeval t;
-     
-     pid = scanner_p->pid;
-     
-     if ( !Ucrit_checkPid(pid) )
-     {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
-       continue;
-     }
+    smb_shm_lock_hash_entry(i);
+    if(mode_array[i] == NULL_OFFSET)
+    {
+      smb_shm_unlock_hash_entry(i);
+      continue;
+    }
+    file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[i]);
+    while((file_scanner_p != 0) && (file_scanner_p->num_share_mode_entries != 0))
+    {
+      share_mode_entry *entry_scanner_p = 
+                 (share_mode_entry *)smb_shm_offset2addr(
+                                       file_scanner_p->share_mode_entries);
+
+      while(entry_scanner_p != 0)
+      {
+        struct timeval t;
+        int pid = entry_scanner_p->pid;
+        int mode = entry_scanner_p->share_mode;
      
-     if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
+        t.tv_sec = entry_scanner_p->time.tv_sec;
+        t.tv_usec = entry_scanner_p->time.tv_usec;
+        strcpy(fname, file_scanner_p->file_name);
+#else /* FAST_SHARE_MODES */
+
+     /* For slow share modes go through all the files in
+        the share mode directory and read the entries in
+        each.
+      */
+
+     dir = opendir(lp_lockdir());
+     if (!dir) 
      {
-       DEBUG(2,("Deleting stale share mode record"));
-       if(prev_p == scanner_p)
-       {
-          smb_shm_set_userdef_off(scanner_p->next_offset);
-          smb_shm_free(smb_shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-           prev_p = scanner_p;
-       }
-       else
-       {
-          prev_p->next_offset = scanner_p->next_offset;
-          smb_shm_free(smb_shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)smb_shm_offset2addr(prev_p->next_offset);
-       }
-       continue;
+       printf("%s: Unable to open lock directory %s.\n", argv[0], lp_lockdir());
+       return(0);
      }
-     t.tv_sec = scanner_p->time.tv_sec;
-     t.tv_usec = scanner_p->time.tv_usec;
-     mode = scanner_p->share_mode;
-     strcpy(fname, scanner_p->file_name);
-#else
-     dir = opendir(lp_lockdir());
-     if (!dir) return(0);
      while ((s=readdirname(dir))) {
-       char buf[20];
-       int pid,mode;
-       struct timeval t;
+       char *buf;
+       char *base;
        int fd;
        pstring lname;
-       int dev,inode;
+       uint32 dev,inode;
        
-       if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
+       if (sscanf(s,"share.%u.%u",&dev,&inode)!=2) continue;
        
        strcpy(lname,lp_lockdir());
        trim_string(lname,NULL,"/");
        strcat(lname,"/");
        strcat(lname,s);
        
-       fd = open(lname,O_RDONLY,0);
-       if (fd < 0) continue;
-       if (read(fd,buf,20) != 20) continue;
-       n = read(fd,fname,sizeof(fname));
-       fname[MAX(n,0)]=0;
-       close(fd);
-       
-       t.tv_sec = IVAL(buf,4);
-       t.tv_usec = IVAL(buf,8);
-       mode = IVAL(buf,12);
-       pid = IVAL(buf,16);
-       
-       if ( !Ucrit_checkPid(pid) )             /* added by OH */
-        continue;
-       
-       if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) {
-        if (unlink(lname)==0)
-          printf("Deleted stale share file %s\n",s);
-        continue;
+       fd = open(lname,O_RDWR,0);
+       if (fd < 0) 
+       {
+         printf("%s: Unable to open share file %s.\n", argv[0], lname);
+         continue;
        }
-#endif
+
+       /* Lock the share mode file while we read it. */
+       if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+       {
+         printf("%s: Unable to lock open share file %s.\n", argv[0], lname);
+         close(fd);
+         continue;
+       }
+
+       if(( buf = read_share_file( fd, lname, argv[0] )) == NULL)
+       {
+         close(fd);
+         continue;
+       } 
+       strcpy( fname, &buf[10]);
+       close(fd);
+      
+       base = buf + 10 + SVAL(buf,8); 
+       for( i = 0; i < IVAL(buf, 4); i++)
+       {
+         char *p = base + (i*16);
+         struct timeval t;
+         int pid = IVAL(p,12);
+         int mode = IVAL(p,8);
+     
+         t.tv_sec = IVAL(p,0);
+         t.tv_usec = IVAL(p,4);
+#endif /* FAST_SHARE_MODES */
 
     fname[sizeof(fname)-1] = 0;
 
@@ -349,28 +433,38 @@ unsigned int   Ucrit_IsActive = 0;                    /* added by OH */
       }
     printf(" %s   %s",fname,asctime(LocalTime((time_t *)&t.tv_sec)));
 
-#if FAST_SHARE_MODES
-     prev_p = scanner_p ;
-     scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
-  } /* end while */
+#ifdef FAST_SHARE_MODES
+
+        entry_scanner_p = (share_mode_entry *)smb_shm_offset2addr(
+                                    entry_scanner_p->next_share_mode_entry);
+      } /* end while entry_scanner_p */
+     file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
+                                    file_scanner_p->next_offset);
+    } /* end while file_scanner_p */
+    smb_shm_unlock_hash_entry(i);
+  } /* end for */
 
   smb_shm_get_usage(&bytes_free, &bytes_used, &bytes_overhead);
   bytes_total = bytes_free + bytes_used + bytes_overhead;
-  smb_shm_unlock();
 
   /*******************************************************************
   deinitialize the shared memory for share_mode management 
   ******************************************************************/
   smb_shm_close();
 
-#else
+#else /* FAST_SHARE_MODES */
+    } /* end for i */
+
+    if(buf)
+      free(buf);
+    base = 0;
   } /* end while */
   closedir(dir);
 
-#endif
+#endif /* FAST_SHARE_MODES */
   if (firstopen)
     printf("No locked files\n");
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
   printf("\nShare mode memory usage (bytes):\n");
   printf("   %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
         bytes_free, (bytes_free * 100)/bytes_total,
@@ -378,7 +472,7 @@ unsigned int   Ucrit_IsActive = 0;                    /* added by OH */
         bytes_overhead, (bytes_overhead * 100)/bytes_total,
         bytes_total);
   
-#endif
+#endif /* FAST_SHARE_MODES */
 
   return (0);
 }