a major share modes reorganisation.
authorAndrew Tridgell <tridge@samba.org>
Mon, 20 Oct 1997 08:46:00 +0000 (08:46 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 20 Oct 1997 08:46:00 +0000 (08:46 +0000)
The shares modes code is now split into separate files. The shared
memory implementation is in locking_shm.c. The slow implementation is
in locking_slow.c

It is all controlled by a struct share_ops structure that has function
pointers to the implementation of all the functions needed by a share
modes implementation. An initialisation function sets up this
structure. This will make adding new implementations easy and clean.

This also allowed me to get rid of the ugly code in smbstatus. Now
status.c links to the locking code and calls methods in share_ops.

I also renamed some things and generally organised things in a much
cleaner fashion. Defines and structures specific to each
implementation have been moved to the appropriate file and out of
smb.h.
(This used to be commit 65ab9adaa0d356b8041ed8a507ea52117f2a284e)

source3/include/proto.h
source3/include/smb.h
source3/locking/locking.c
source3/locking/locking_shm.c [new file with mode: 0644]
source3/locking/locking_slow.c [new file with mode: 0644]
source3/smbd/reply.c
source3/smbd/server.c
source3/utils/status.c

index 224aaa5a79c965ccd02222d9b5a4665143726a35..024917a0d817bc22c5f4821aa968073695e06121 100644 (file)
@@ -305,22 +305,25 @@ int lp_minor_announce_version(void);
 BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset);
 BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode);
 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);
-BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok);
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token 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, uint16 port, uint16 op_type);
-BOOL remove_share_oplock(int fnum, share_lock_token token);
-BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok);
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token 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, uint16 port, uint16 op_type);
-BOOL remove_share_oplock(int fnum, share_lock_token token);
+BOOL locking_init(void);
+BOOL locking_end(void);
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok);
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token);
+int get_share_modes(int cnum, int token, uint32 dev, uint32 inode, 
+                   share_mode_entry **shares);
+void del_share_mode(int token, int fnum);
+BOOL set_share_mode(int token, int fnum, uint16 port, uint16 op_type);
+BOOL remove_share_oplock(int fnum, int token);
+int share_mode_forall(void (*fn)(share_mode_entry *, char *));
+void share_status(FILE *f);
+
+/*The following definitions come from  locking_shm.c  */
+
+struct share_ops *locking_shm_init(void);
+
+/*The following definitions come from  locking_slow.c  */
+
+struct share_ops *locking_slow_init(void);
 
 /*The following definitions come from  lsaparse.c  */
 
@@ -778,7 +781,7 @@ BOOL check_name(char *name,int cnum);
 void sync_file(int fnum);
 void close_file(int fnum, BOOL normal_close);
 BOOL check_file_sharing(int cnum,char *fname);
-int check_share_mode( min_share_mode_entry *share, int deny_mode, char *fname,
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
                       BOOL fcbopen, int *flags);
 void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
                      int mode,int oplock_request, int *Access,int *action);
@@ -791,7 +794,7 @@ int cached_error_packet(char *inbuf,char *outbuf,int fnum,int line);
 int unix_error_packet(char *inbuf,char *outbuf,int def_class,uint32 def_code,int line);
 int error_packet(char *inbuf,char *outbuf,int error_class,uint32 error_code,int line);
 BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval);
-BOOL request_oplock_break(min_share_mode_entry *share_entry, 
+BOOL request_oplock_break(share_mode_entry *share_entry, 
                           uint32 dev, uint32 inode);
 BOOL snum_used(int snum);
 BOOL reload_services(BOOL test);
index 0d10bd58954d58f3825e97f8b71db9bdda59a90d..ff6cc7eb25d36d3669aaea388b00d74ee0fe154c 100644 (file)
@@ -1195,29 +1195,6 @@ struct interface
        struct in_addr nmask;
 };
 
-/* share mode record pointed to in shared memory hash bucket */
-typedef struct
-{
-  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;
-  uint16 op_port;
-  uint16 op_type;
-  int share_mode;
-  struct timeval time;
-} share_mode_entry;
-
 /* struct returned by get_share_modes */
 typedef struct
 {
@@ -1226,14 +1203,26 @@ typedef struct
   uint16 op_type;
   int share_mode;
   struct timeval time;
-} min_share_mode_entry;
+} 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())
 
+/* each implementation of the share mode code needs
+   to support the following operations */
+struct share_ops {
+       BOOL (*stop_mgmt)(void);
+       BOOL (*lock_entry)(int , uint32 , uint32 , int *);
+       BOOL (*unlock_entry)(int , uint32 , uint32 , int );
+       BOOL (*get_entries)(int , int , uint32 , uint32 , share_mode_entry **);
+       void (*del_entry)(int , int );
+       BOOL (*set_entry)(int , int , uint16 , uint16 );
+       BOOL (*remove_oplock)(int , int);
+       int (*forall)(void (*)(share_mode_entry *, char *));
+       void (*status)(FILE *);
+};
+
 /* this is used for smbstatus */
 struct connect_record
 {
@@ -1252,34 +1241,6 @@ struct connect_record
 #define LOCKING_VERSION 4
 #endif /* LOCKING_VERSION */
 
-#if !defined(FAST_SHARE_MODES)
-/* 
- * Defines for slow share modes.
- */
-
-/* 
- * Locking file header lengths & offsets. 
- */
-#define SMF_VERSION_OFFSET 0
-#define SMF_NUM_ENTRIES_OFFSET 4
-#define SMF_FILENAME_LEN_OFFSET 8
-#define SMF_HEADER_LENGTH 10
-
-#define SMF_ENTRY_LENGTH 20
-
-/*
- * Share mode record offsets.
- */
-
-#define SME_SEC_OFFSET 0
-#define SME_USEC_OFFSET 4
-#define SME_SHAREMODE_OFFSET 8
-#define SME_PID_OFFSET 12
-#define SME_PORT_OFFSET 16
-#define SME_OPLOCK_TYPE_OFFSET 18
-
-#endif /* FAST_SHARE_MODES */
-
 /* these are useful macros for checking validity of handles */
 #define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < MAX_OPEN_FILES))
 #define OPEN_FNUM(fnum)    (VALID_FNUM(fnum) && Files[fnum].open)
index bbc0c0033fffc7d5470fc5585cd6cade70754f29..c75497c6b920a278d032fed667758772e9af2078 100644 (file)
@@ -36,6 +36,8 @@ extern int DEBUGLEVEL;
 extern connection_struct Connections[];
 extern files_struct Files[];
 
+static struct share_ops *share_ops;
+
 /****************************************************************************
   utility function called to see if a file region is locked
 ****************************************************************************/
@@ -104,1460 +106,102 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
   return True; /* Did unlock */
 }
 
-#ifdef FAST_SHARE_MODES
-/*******************************************************************
-  initialize the shared memory for share_mode management 
-  ******************************************************************/
-BOOL start_share_mode_mgmt(void)
-{
-   pstring shmem_file_name;
-   
-  pstrcpy(shmem_file_name,lp_lockdir());
-  if (!directory_exist(shmem_file_name,NULL))
-    mkdir(shmem_file_name,0755);
-  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, lp_shmem_size());
-}
 
 
-/*******************************************************************
-  deinitialize the shared memory for share_mode management 
-  ******************************************************************/
-BOOL stop_share_mode_mgmt(void)
+/****************************************************************************
+  initialise the locking functions
+****************************************************************************/
+BOOL locking_init(void)
 {
-   return smb_shm_close();
-}
+#ifdef FAST_SHARE_MODES
+       share_ops = locking_shm_init();
+       if (!share_ops) {
+               DEBUG(0,("ERROR: Failed to initialise fast share modes - trying slow code\n"));
+       }
+       if (share_ops) return True;
+#endif 
 
-/*******************************************************************
-  lock a hash bucket entry in shared memory for share_mode management 
-  ******************************************************************/
-BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
-{
-  return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
+       share_ops = locking_slow_init();
+       if (!share_ops) {
+               DEBUG(0,("ERROR: Failed to initialise share modes!\n"));
+               return False;
+       }
+       
+       return True;
 }
 
 /*******************************************************************
-  unlock a hash bucket entry in shared memory for share_mode management 
+  deinitialize the share_mode management 
   ******************************************************************/
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+BOOL locking_end(void)
 {
-  return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
+       return share_ops->stop_mgmt();
 }
 
-/*******************************************************************
-get all share mode entries in shared memory 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)
-{
-  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;
-
-  *old_shares = 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() ));
-    return 0;
-  }
-
-  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  
-  if(mode_array[hash_entry] == NULL_OFFSET)
-  {
-    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
-    {
-      file_prev_p = file_scanner_p ;
-      file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
-                                    file_scanner_p->next_offset);
-    }
-  }
-  
-  if(!found)
-  {
-    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(file_scanner_p->locking_version != LOCKING_VERSION)
-  {
-    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\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 (0);
-  }
-
-  /* Allocate the old_shares array */
-  num_entries = file_scanner_p->num_share_mode_entries;
-  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 (FAST_SHARE_MODES): malloc fail !\n"));
-      return 0;
-    }
-  }
-
-  num_entries_copied = 0;
-  
-  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)
-  {
-    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;
-      int share_mode = entry_scanner_p->share_mode;
-
-      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));
-        return 0;
-      }
-
-      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 %d (number of entries now = %d)\n", 
-            pid, 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;
-       share_array[num_entries_copied].op_port = entry_scanner_p->op_port;
-       share_array[num_entries_copied].op_type = entry_scanner_p->op_type;
-       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 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));
-  }
-
-  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);
-}  
 
 /*******************************************************************
-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();
-
-  dev = Files[fnum].fd_ptr->dev;
-  inode = Files[fnum].fd_ptr->inode;
-
-  hash_entry = HASH_ENTRY(dev, inode);
-
-  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() ));
-    return;
-  }
-
-  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));
-    return;
-  }  
-  
-  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
-    {
-      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;
-  }
-
-  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 (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));
-      return;
-    }
-
-    /* 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));
-  }
-}
-
-/*******************************************************************
-set the share mode of a file. Return False on fail, True on success.
-********************************************************************/
-BOOL set_share_mode(share_lock_token token, int fnum, uint16 port, uint16 op_type)
-{
-  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;
-
-  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() ));
-    return False;
-  }
-
-  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;
-  
-  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)
-  {
-    /* 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;
-  }
-
-  new_entry_p = smb_shm_offset2addr(new_entry_offset);
-
-  new_entry_p->pid = getpid();
-  new_entry_p->share_mode = fs_p->share_mode;
-  new_entry_p->op_port = port;
-  new_entry_p->op_type = op_type;
-  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(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));
-    return False;
-  }
-
-  /* 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);
-}
-
-/*******************************************************************
-Remove an oplock port and mode entry from a share mode.
-********************************************************************/
-BOOL remove_share_oplock(int fnum, share_lock_token token)
-{
-  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();
-
-  dev = Files[fnum].fd_ptr->dev;
-  inode = Files[fnum].fd_ptr->inode;
-
-  hash_entry = HASH_ENTRY(dev, inode);
-
-  if(hash_entry > lp_shmem_hash_size() )
-  {
-    DEBUG(0,
-      ("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash_entry %d too large \
-(max = %d)\n",
-      hash_entry, lp_shmem_hash_size() ));
-    return False;
-  }
-
-  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:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
-                  hash_entry));
-    return False;
-  } 
-    
-  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
-    {
-      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:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
-inode %d in hash bucket %d\n", dev, inode, hash_entry));
-     return False;
-  } 
-
-  if(file_scanner_p->locking_version != LOCKING_VERSION)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock (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 False;
-  }
-
-  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) && 
-        (entry_scanner_p->share_mode == Files[fnum].share_mode) &&
-        (memcmp(&entry_scanner_p->time, 
-                &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
-    {
-      /* Delete the oplock info. */
-      entry_scanner_p->op_port = 0;
-      entry_scanner_p->op_type = 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(!found)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
-mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
-    return False;
-  }
-
-  return True;
-}
-
-#else /* FAST_SHARE_MODES */
-
-/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
-
-/*******************************************************************
-  name a share file
+  lock a hash bucket entry 
   ******************************************************************/
-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);
-}
-
-/*******************************************************************
-Force a share file to be deleted.
-********************************************************************/
-
-static int delete_share_file( int cnum, char *fname )
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
 {
-  /* the share file could be owned by anyone, so do this as root */
-  become_root(False);
-
-  if(unlink(fname) != 0)
-  {
-    DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
-            fname, strerror(errno)));
-  } 
-  else 
-  {
-    DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
-  }
-
-  /* return to our previous privilage level */
-  unbecome_root(False);
-
-  return 0;
+       return share_ops->lock_entry(cnum, dev, inode, ptok);
 }
 
 /*******************************************************************
-  lock a share mode file.
+  unlock a hash bucket entry
   ******************************************************************/
-BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
 {
-  pstring fname;
-  int fd;
-  int ret = True;
-
-  *ptok = (share_lock_token)-1;
-
-  if(!share_name(cnum, dev, inode, fname))
-    return False;
-
-  /* we need to do this as root */
-  become_root(False);
-
-  {
-    int old_umask;
-    BOOL gotlock = False;
-    old_umask = umask(0);
-
-    /*
-     * There was a race condition in the original slow share mode code.
-     * A smbd could open a share mode file, and before getting
-     * the lock, another smbd could delete the last entry for
-     * the share mode file and delete the file entry from the
-     * directory. Thus this smbd would be left with a locked
-     * share mode fd attached to a file that no longer had a
-     * directory entry. Thus another smbd would think that
-     * there were no outstanding opens on the file. To fix
-     * this we now check we can do a stat() call on the filename
-     * before allowing the lock to proceed, and back out completely
-     * and try the open again if we cannot.
-     * Jeremy Allison (jallison@whistle.com).
-     */
-
-    do
-    {
-      struct stat dummy_stat;
-
-#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,0666);
-#endif /* SECURE_SHARE_MODES */
-
-      if(fd < 0)
-      {
-        DEBUG(0,("ERROR lock_share_entry: failed to open share file %s. Error was %s\n",
-                  fname, strerror(errno)));
-        ret = False;
-        break;
-      }
-
-       /* 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 on file %s failed with %s\n",
-                  fname, strerror(errno)));   
-        close(fd);
-        ret = False;
-        break;
-      }
-
-      /* 
-       * If we cannot stat the filename, the file was deleted between
-       * the open and the lock call. Back out and try again.
-       */
-
-      if(stat(fname, &dummy_stat)!=0)
-      {
-        DEBUG(2,("lock_share_entry: Re-issuing open on %s to fix race. Error was %s\n",
-                fname, strerror(errno)));
-        close(fd);
-      }
-      else
-        gotlock = True;
-    } while(!gotlock);
-
-    /*
-     * We have to come here if any of the above calls fail
-     * as we don't want to return and leave ourselves running
-     * as root !
-     */
-
-    umask(old_umask);
-  }
-
-  *ptok = (share_lock_token)fd;
-
-  /* return to our previous privilage level */
-  unbecome_root(False);
-
-  return ret;
+       return share_ops->unlock_entry(cnum, dev, inode, token);
 }
 
 /*******************************************************************
-  unlock a share mode file.
-  ******************************************************************/
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+get all share mode entries for a dev/inode pair.
+********************************************************************/
+int get_share_modes(int cnum, int token, uint32 dev, uint32 inode, 
+                   share_mode_entry **shares)
 {
-  int fd = (int)token;
-  int ret = True;
-  struct stat sb;
-  pstring fname;
-
-  /* Fix for zero length share files from
-     Gerald Werner <wernerg@mfldclin.edu> */
-    
-  share_name(cnum, dev, inode, fname);
-
-  /* get the share mode file size */
-  if(fstat((int)token, &sb) != 0)
-  {
-    DEBUG(0,("ERROR: unlock_share_entry: Failed to do stat on share file %s (%s)\n",
-              fname, strerror(errno)));
-    sb.st_size = 1;
-    ret = False;
-  }
-
-  /* If the file was zero length, we must delete before
-     doing the unlock to avoid a race condition (see
-     the code in lock_share_mode_entry for details.
-   */
-
-  /* remove the share file if zero length */    
-  if(sb.st_size == 0)  
-    delete_share_file(cnum, fname);
-
-  /* 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(fd);
-  return ret;
+       return share_ops->get_entries(cnum, token, dev, inode, shares);
 }
 
 /*******************************************************************
-Read a share file into a buffer.
+del the share mode of a file.
 ********************************************************************/
-
-static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
+void del_share_mode(int token, int fnum)
 {
-  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 (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 (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
-    DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
-locking version (was %d, should be %d).\n",fname, 
-                    IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION));
-   if(buf)
-      free(buf);
-    delete_share_file(cnum, fname);
-    return -1;
-  }
-
-  /* Sanity check for file contents */
-  size = sb.st_size;
-  size -= SMF_HEADER_LENGTH; /* Remove the header */
-
-  /* Remove the filename component. */
-  size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
-
-  /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
-  if((size % SMF_ENTRY_LENGTH) != 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;
-  }
-
-  *out = buf;
-  return 0;
+       share_ops->del_entry(token, fnum);
 }
 
 /*******************************************************************
-get all share mode entries in a share file for a dev/inode pair.
+set the share mode of a file. Return False on fail, True on success.
 ********************************************************************/
-int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
-                    min_share_mode_entry **old_shares)
+BOOL set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
 {
-  int fd = (int)token;
-  pstring fname;
-  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).
-
-   Followed by <n> share mode entries of the form :
-
-     0   -  tv_sec
-     4   -  tv_usec
-     8   -  share_mode
-    12   -  pid
-    16   -  oplock port (if oplocks in use) - 2 bytes.
-  */
-
-  share_name(cnum, dev, inode, fname);
-
-  if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
-  {
-    DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
-                  fname));
-    return 0;
-  }
-
-  if(new_file == True)
-    return 0;
-
-  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
-
-  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));
-    return 0;
-  }
-
-  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;
-  }
-
-  num_entries_copied = 0;
-  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
-
-  for( i = 0; i < num_entries; i++)
-  {
-    int pid;
-    char *p = base + (i*SMF_ENTRY_LENGTH);
-
-    pid = IVAL(p,SME_PID_OFFSET);
-
-    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,SME_SHAREMODE_OFFSET), fname));
-      continue;
-    }
-    share_array[num_entries_copied].time.tv_sec = IVAL(p,SME_SEC_OFFSET);
-    share_array[num_entries_copied].time.tv_usec = IVAL(p,SME_USEC_OFFSET);
-    share_array[num_entries_copied].share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
-    share_array[num_entries_copied].pid = pid;
-    share_array[num_entries_copied].op_port = SVAL(p,SME_PORT_OFFSET);
-    share_array[num_entries_copied].op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
-
-    num_entries_copied++;
-  }
-
-  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);
-    *old_shares = 0;
-    if(buf)
-      free(buf);
-    delete_share_file(cnum, fname);
-    return 0;
-  }
-
-  /* If we deleted some entries we need to re-write the whole number of
-     share mode entries back into the file. */
-
-  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);
-      *old_shares = 0;
-      if(buf)
-        free(buf);
-      return 0;
-    }
-
-    SIVAL(buf, SMF_NUM_ENTRIES_OFFSET, num_entries_copied);
-    for( i = 0; i < num_entries_copied; i++)
-    {
-      char *p = base + (i*SMF_ENTRY_LENGTH);
-
-      SIVAL(p,SME_PID_OFFSET,share_array[i].pid);
-      SIVAL(p,SME_SHAREMODE_OFFSET,share_array[i].share_mode);
-      SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
-      SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
-      SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
-      SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
-    }
-
-    newsize = (base - buf) + (SMF_ENTRY_LENGTH*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);
-      *old_shares = 0;
-      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);
-      *old_shares = 0;
-      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;
+       return share_ops->set_entry(token, fnum, port, op_type);
 }
 
 /*******************************************************************
-del a share mode from a share mode file.
+Remove an oplock port and mode entry from a share mode.
 ********************************************************************/
-void del_share_mode(share_lock_token token, int fnum)
+BOOL remove_share_oplock(int fnum, int token)
 {
-  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;
-  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)
-  {
-    DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
-                  fname));
-    return;
-  }
-
-  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;
-  }
-
-  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
-
-  DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
-            fname, num_entries));
-
-  /* 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));
-    return;
-  }
-
-  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;
-  }
-
-  pid = getpid();
-
-  /* Go through the entries looking for the particular one
-     we have set - delete it.
-  */
-
-  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
-
-  for(i = 0; i < num_entries; i++)
-  {
-    char *p = base + (i*SMF_ENTRY_LENGTH);
-
-    if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) || 
-       (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
-       (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) || 
-       (IVAL(p,SME_PID_OFFSET) != 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 + SMF_ENTRY_LENGTH, (num_entries - i - 1)*SMF_ENTRY_LENGTH);
-
-    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,SMF_NUM_ENTRIES_OFFSET, 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;
-  }
+       return share_ops->remove_oplock(fnum, token);
+}
 
-  /* 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;
-  }
 
-  newsize = (base - buf) + (SMF_ENTRY_LENGTH*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
+call the specified function on each entry under management by the
+share mode system
 ********************************************************************/
-BOOL set_share_mode(share_lock_token token,int fnum, uint16 port, uint16 op_type)
+int share_mode_forall(void (*fn)(share_mode_entry *, char *))
 {
-  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;
-  }
-
-  /* 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 + SMF_ENTRY_LENGTH)) == NULL)
-    {
-      DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", 
-                  sb.st_size + SMF_ENTRY_LENGTH));
-      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,SMF_VERSION_OFFSET) != LOCKING_VERSION) 
-    {
-      DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
-locking version (was %d, should be %d).\n",fname, IVAL(buf,SMF_VERSION_OFFSET), 
-                    LOCKING_VERSION));
-      if(buf)
-        free(buf);
-      delete_share_file(fs_p->cnum, fname);
-      return False;
-    }   
-
-    size -= (SMF_HEADER_LENGTH + SVAL(buf, SMF_FILENAME_LEN_OFFSET)); /* Remove the header */
-
-    /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
-    if((size % SMF_ENTRY_LENGTH) != 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(SMF_HEADER_LENGTH + 
-                  strlen(fs_p->name) + 1 + SMF_ENTRY_LENGTH)) == NULL)
-    {
-      DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
-      return False;
-    }
-    SIVAL(buf,SMF_VERSION_OFFSET,LOCKING_VERSION);
-    SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,0);
-    SSVAL(buf,SMF_FILENAME_LEN_OFFSET,strlen(fs_p->name) + 1);
-    strcpy(buf + SMF_HEADER_LENGTH, fs_p->name);
-  }
-
-  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
-  header_size = SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
-  p = buf + header_size + (num_entries * SMF_ENTRY_LENGTH);
-  SIVAL(p,SME_SEC_OFFSET,fs_p->open_time.tv_sec);
-  SIVAL(p,SME_USEC_OFFSET,fs_p->open_time.tv_usec);
-  SIVAL(p,SME_SHAREMODE_OFFSET,fs_p->share_mode);
-  SIVAL(p,SME_PID_OFFSET,pid);
-  SSVAL(p,SME_PORT_OFFSET,port);
-  SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
-
-  num_entries++;
-
-  SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,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*SMF_ENTRY_LENGTH)) != 
-                       (header_size + (num_entries*SMF_ENTRY_LENGTH))) 
-  {
-    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 + (SMF_ENTRY_LENGTH*num_entries))!= 0)
-  {
-    DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
-mode file %s to size %d (%s)\n", fname, header_size + (SMF_ENTRY_LENGTH*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));
-
-  return True;
+       return share_ops->forall(fn);
 }
 
 /*******************************************************************
-Remove an oplock port and mode entry from a share mode.
+dump the state of the system
 ********************************************************************/
-BOOL remove_share_oplock(int fnum, share_lock_token token)
+void share_status(FILE *f)
 {
-  pstring fname;
-  int fd = (int)token;
-  char *buf = 0;
-  char *base = 0;
-  int num_entries;
-  int fsize;
-  int i;
-  files_struct *fs_p = &Files[fnum];
-  int pid;
-  BOOL found = 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)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
-                  fname));
-    return False;
-  }
-
-  if(new_file == True)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
-deleting it.\n", fname));
-    delete_share_file(fs_p->cnum, fname);
-    return False;
-  }
-
-  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
-
-  DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
-            fname, num_entries));
-
-  /* PARANOIA TEST */
-  if(num_entries < 0)
-  {
-    DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
-for share file %d\n", num_entries, fname));
-    return False;
-  }
-
-  if(num_entries == 0)
-  {
-    /* No entries - just delete the file. */
-    DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
-              fname));
-    if(buf)
-      free(buf);
-    delete_share_file(fs_p->cnum, fname);
-    return False;
-  }
-
-  pid = getpid();
-
-  /* Go through the entries looking for the particular one
-     we have set - remove the oplock settings on it.
-  */
-
-  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
-
-  for(i = 0; i < num_entries; i++)
-  {
-    char *p = base + (i*SMF_ENTRY_LENGTH);
-
-    if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) || 
-       (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
-       (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) || 
-       (IVAL(p,SME_PID_OFFSET) != pid))
-      continue;
-
-    DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
-from the share file %s\n", i, num_entries, fname));
-
-    SSVAL(p,SME_PORT_OFFSET,0);
-    SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
-    found = True;
-    break;
-  }
-
-  if(!found)
-  {
-    DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
-    if(buf)
-      free(buf);
-    return False;
-  }
-
-  /* Re-write the file - and truncate it at the correct point. */
-  if(lseek(fd, 0, SEEK_SET) != 0)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
-position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
-    if(buf)
-      free(buf);
-    return False;
-  }
-
-  fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
-  if(write(fd, buf, fsize) != fsize)
-  {
-    DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
-mode file %s (%s)\n", fname, strerror(errno)));
-    if(buf)
-      free(buf);
-    return False;
-  }
-
-  return True;
-
+       share_ops->status(f);
 }
-#endif /* FAST_SHARE_MODES */
diff --git a/source3/locking/locking_shm.c b/source3/locking/locking_shm.c
new file mode 100644 (file)
index 0000000..99d981e
--- /dev/null
@@ -0,0 +1,739 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   shared memory locking implementation
+   Copyright (C) Andrew Tridgell 1992-1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   Revision History:
+
+   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.
+
+   September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+   support.
+
+   October 1997 - split into separate file (tridge)
+*/
+
+#ifdef FAST_SHARE_MODES
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+extern connection_struct Connections[];
+extern files_struct Files[];
+
+/* share mode record pointed to in shared memory hash bucket */
+typedef struct
+{
+  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;
+       share_mode_entry e;
+} shm_share_mode_entry;
+
+
+/*******************************************************************
+  deinitialize the shared memory for share_mode management 
+  ******************************************************************/
+static BOOL shm_stop_share_mode_mgmt(void)
+{
+   return smb_shm_close();
+}
+
+/*******************************************************************
+  lock a hash bucket entry in shared memory for share_mode management 
+  ******************************************************************/
+static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
+{
+  return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+  unlock a hash bucket entry in shared memory for share_mode management 
+  ******************************************************************/
+static BOOL shm_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
+{
+  return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
+}
+
+/*******************************************************************
+get all share mode entries in shared memory for a dev/inode pair.
+********************************************************************/
+static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, 
+                              share_mode_entry **old_shares)
+{
+  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;
+  shm_share_mode_entry *entry_scanner_p;
+  shm_share_mode_entry *entry_prev_p;
+  int num_entries;
+  int num_entries_copied;
+  BOOL found = False;
+  share_mode_entry *share_array = (share_mode_entry *)0;
+
+  *old_shares = 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() ));
+    return 0;
+  }
+
+  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+  
+  if(mode_array[hash_entry] == NULL_OFFSET)
+  {
+    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
+    {
+      file_prev_p = file_scanner_p ;
+      file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
+                                    file_scanner_p->next_offset);
+    }
+  }
+  
+  if(!found)
+  {
+    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(file_scanner_p->locking_version != LOCKING_VERSION)
+  {
+    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\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 (0);
+  }
+
+  /* Allocate the old_shares array */
+  num_entries = file_scanner_p->num_share_mode_entries;
+  if(num_entries)
+  {
+    *old_shares = share_array = (share_mode_entry *)
+                 malloc(num_entries * sizeof(share_mode_entry));
+    if(*old_shares == 0)
+    {
+      DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
+      return 0;
+    }
+  }
+
+  num_entries_copied = 0;
+  
+  entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr(
+                                           file_scanner_p->share_mode_entries);
+  entry_prev_p = entry_scanner_p;
+  while(entry_scanner_p)
+  {
+    int pid = entry_scanner_p->e.pid;
+
+    if (pid && !process_exists(pid))
+    {
+      /* Delete this share mode entry */
+      shm_share_mode_entry *delete_entry_p = entry_scanner_p;
+      int share_mode = entry_scanner_p->e.share_mode;
+
+      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 = (shm_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 = (shm_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));
+        return 0;
+      }
+
+      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 %d (number of entries now = %d)\n", 
+            pid, 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->e.pid;
+       share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
+       share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
+       share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
+       memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.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->e.share_mode, entry_scanner_p->e.pid));
+       entry_prev_p = entry_scanner_p;
+       entry_scanner_p = (shm_share_mode_entry *)
+                           smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+    }
+  }
+  
+  /* 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));
+  }
+
+  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);
+}  
+
+/*******************************************************************
+del the share mode of a file.
+********************************************************************/
+static void shm_del_share_mode(int 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;
+  shm_share_mode_entry *entry_scanner_p;
+  shm_share_mode_entry *entry_prev_p;
+  BOOL found = False;
+  int pid = getpid();
+
+  dev = Files[fnum].fd_ptr->dev;
+  inode = Files[fnum].fd_ptr->inode;
+
+  hash_entry = HASH_ENTRY(dev, inode);
+
+  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() ));
+    return;
+  }
+
+  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));
+    return;
+  }  
+  
+  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
+    {
+      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;
+  }
+
+  found = False;
+  entry_scanner_p = (shm_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->e.pid) && 
+          (memcmp(&entry_scanner_p->e.time, 
+                 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+    {
+      found = True;
+      break;
+    }
+    else
+    {
+      entry_prev_p = entry_scanner_p;
+      entry_scanner_p = (shm_share_mode_entry *)
+                          smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+    }
+  } 
+
+  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));
+      return;
+    }
+
+    /* 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));
+  }
+}
+
+/*******************************************************************
+set the share mode of a file. Return False on fail, True on success.
+********************************************************************/
+static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
+{
+  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;
+  shm_share_mode_entry *new_entry_p;
+  smb_shm_offset_t new_entry_offset;
+  BOOL found = False;
+
+  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() ));
+    return False;
+  }
+
+  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;
+  
+  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)
+  {
+    /* 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(shm_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;
+  }
+
+  new_entry_p = smb_shm_offset2addr(new_entry_offset);
+
+  new_entry_p->e.pid = getpid();
+  new_entry_p->e.share_mode = fs_p->share_mode;
+  new_entry_p->e.op_port = port;
+  new_entry_p->e.op_type = op_type;
+  memcpy( (char *)&new_entry_p->e.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(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));
+    return False;
+  }
+
+  /* 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->e.pid,
+                             file_scanner_p->num_share_mode_entries));
+
+  return(True);
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL shm_remove_share_oplock(int fnum, int token)
+{
+  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;
+  shm_share_mode_entry *entry_scanner_p;
+  shm_share_mode_entry *entry_prev_p;
+  BOOL found = False;
+  int pid = getpid();
+
+  dev = Files[fnum].fd_ptr->dev;
+  inode = Files[fnum].fd_ptr->inode;
+
+  hash_entry = HASH_ENTRY(dev, inode);
+
+  if(hash_entry > lp_shmem_hash_size() )
+  {
+    DEBUG(0,
+      ("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+      hash_entry, lp_shmem_hash_size() ));
+    return False;
+  }
+
+  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:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
+                  hash_entry));
+    return False;
+  } 
+    
+  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
+    {
+      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:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+     return False;
+  } 
+
+  if(file_scanner_p->locking_version != LOCKING_VERSION)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock (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 False;
+  }
+
+  found = False;
+  entry_scanner_p = (shm_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->e.pid) && 
+        (entry_scanner_p->e.share_mode == Files[fnum].share_mode) &&
+        (memcmp(&entry_scanner_p->e.time, 
+                &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+    {
+      /* Delete the oplock info. */
+      entry_scanner_p->e.op_port = 0;
+      entry_scanner_p->e.op_type = 0;
+      found = True;
+      break;
+    }
+    else
+    {
+      entry_prev_p = entry_scanner_p;
+      entry_scanner_p = (shm_share_mode_entry *)
+                          smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+    }
+  } 
+
+  if(!found)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
+mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+    return False;
+  }
+
+  return True;
+}
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share ode system
+********************************************************************/
+static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+       int i, count=0;
+       smb_shm_offset_t *mode_array;
+       share_mode_record *file_scanner_p;
+
+       mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+       for( i = 0; i < lp_shmem_hash_size(); i++) {
+               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)) {
+                       shm_share_mode_entry *entry_scanner_p = 
+                               (shm_share_mode_entry *)
+                               smb_shm_offset2addr(file_scanner_p->share_mode_entries);
+
+                       while(entry_scanner_p != 0) {
+                               
+                               fn(&entry_scanner_p->e, 
+                                  file_scanner_p->file_name);
+
+                               entry_scanner_p = 
+                                       (shm_share_mode_entry *)
+                                       smb_shm_offset2addr(
+                                                           entry_scanner_p->next_share_mode_entry);
+                               count++;
+                       } /* 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 */
+
+       return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void shm_share_status(FILE *f)
+{
+       int bytes_free, bytes_used, bytes_overhead, bytes_total;
+
+       smb_shm_get_usage(&bytes_free, &bytes_used, &bytes_overhead);
+       bytes_total = bytes_free + bytes_used + bytes_overhead;
+
+       fprintf(f, "Share mode memory usage (bytes):\n");
+       fprintf(f, "   %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
+               bytes_free, (bytes_free * 100)/bytes_total,
+               bytes_used, (bytes_used * 100)/bytes_total,
+               bytes_overhead, (bytes_overhead * 100)/bytes_total,
+               bytes_total);
+}
+
+
+static struct share_ops share_ops = {
+       shm_stop_share_mode_mgmt,
+       shm_lock_share_entry,
+       shm_unlock_share_entry,
+       shm_get_share_modes,
+       shm_del_share_mode,
+       shm_set_share_mode,
+       shm_remove_share_oplock,
+       shm_share_forall,
+       shm_share_status,
+};
+
+/*******************************************************************
+  initialize the shared memory for share_mode management 
+  ******************************************************************/
+struct share_ops *locking_shm_init(void)
+{
+       pstring shmem_file_name;
+   
+       pstrcpy(shmem_file_name,lp_lockdir());
+       if (!directory_exist(shmem_file_name,NULL))
+               mkdir(shmem_file_name,0755);
+       trim_string(shmem_file_name,"","/");
+       if (!*shmem_file_name) return(False);
+       strcat(shmem_file_name, "/SHARE_MEM_FILE");
+       if (smb_shm_open(shmem_file_name, lp_shmem_size()))
+               return &share_ops;
+       return NULL;
+}
+
+#else
+ int locking_shm_dummy_procedure(void)
+{return 0;}
+#endif
+
+
+
diff --git a/source3/locking/locking_slow.c b/source3/locking/locking_slow.c
new file mode 100644 (file)
index 0000000..cc646c6
--- /dev/null
@@ -0,0 +1,1039 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   slow (lockfile) locking implementation
+   Copyright (C) Andrew Tridgell 1992-1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   Revision History:
+
+   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.
+
+   September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
+   support.
+
+   October 1997 - split into separate file (tridge)
+*/
+
+#include "includes.h"
+extern int DEBUGLEVEL;
+extern connection_struct Connections[];
+extern files_struct Files[];
+
+/* 
+ * Locking file header lengths & offsets. 
+ */
+#define SMF_VERSION_OFFSET 0
+#define SMF_NUM_ENTRIES_OFFSET 4
+#define SMF_FILENAME_LEN_OFFSET 8
+#define SMF_HEADER_LENGTH 10
+
+#define SMF_ENTRY_LENGTH 20
+
+/*
+ * Share mode record offsets.
+ */
+
+#define SME_SEC_OFFSET 0
+#define SME_USEC_OFFSET 4
+#define SME_SHAREMODE_OFFSET 8
+#define SME_PID_OFFSET 12
+#define SME_PORT_OFFSET 16
+#define SME_OPLOCK_TYPE_OFFSET 18
+
+
+/*******************************************************************
+  deinitialize share_mode management 
+  ******************************************************************/
+static BOOL slow_stop_share_mode_mgmt(void)
+{
+   return True;
+}
+
+
+/*******************************************************************
+  name a share file
+  ******************************************************************/
+static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
+{
+  strcpy(name,lp_lockdir());
+  trim_string(name,"","/");
+  if (!*name) return(False);
+  name += strlen(name);
+  
+  sprintf(name,"/share.%u.%u",dev,inode);
+  return(True);
+}
+
+/*******************************************************************
+Force a share file to be deleted.
+********************************************************************/
+static int delete_share_file( int cnum, char *fname )
+{
+  /* the share file could be owned by anyone, so do this as root */
+  become_root(False);
+
+  if(unlink(fname) != 0)
+  {
+    DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
+            fname, strerror(errno)));
+  } 
+  else 
+  {
+    DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
+  }
+
+  /* return to our previous privilage level */
+  unbecome_root(False);
+
+  return 0;
+}
+
+/*******************************************************************
+  lock a share mode file.
+  ******************************************************************/
+static BOOL slow_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
+{
+  pstring fname;
+  int fd;
+  int ret = True;
+
+  *ptok = (int)-1;
+
+  if(!share_name(cnum, dev, inode, fname))
+    return False;
+
+  /* we need to do this as root */
+  become_root(False);
+
+  {
+    int old_umask;
+    BOOL gotlock = False;
+    old_umask = umask(0);
+
+    /*
+     * There was a race condition in the original slow share mode code.
+     * A smbd could open a share mode file, and before getting
+     * the lock, another smbd could delete the last entry for
+     * the share mode file and delete the file entry from the
+     * directory. Thus this smbd would be left with a locked
+     * share mode fd attached to a file that no longer had a
+     * directory entry. Thus another smbd would think that
+     * there were no outstanding opens on the file. To fix
+     * this we now check we can do a stat() call on the filename
+     * before allowing the lock to proceed, and back out completely
+     * and try the open again if we cannot.
+     * Jeremy Allison (jallison@whistle.com).
+     */
+
+    do
+    {
+      struct stat dummy_stat;
+
+#ifdef SECURE_SHARE_MODES
+      fd = (int)open(fname,O_RDWR|O_CREAT,0600);
+#else /* SECURE_SHARE_MODES */
+      fd = (int)open(fname,O_RDWR|O_CREAT,0666);
+#endif /* SECURE_SHARE_MODES */
+
+      if(fd < 0)
+      {
+        DEBUG(0,("ERROR lock_share_entry: failed to open share file %s. Error was %s\n",
+                  fname, strerror(errno)));
+        ret = False;
+        break;
+      }
+
+       /* 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 on file %s failed with %s\n",
+                  fname, strerror(errno)));   
+        close(fd);
+        ret = False;
+        break;
+      }
+
+      /* 
+       * If we cannot stat the filename, the file was deleted between
+       * the open and the lock call. Back out and try again.
+       */
+
+      if(stat(fname, &dummy_stat)!=0)
+      {
+        DEBUG(2,("lock_share_entry: Re-issuing open on %s to fix race. Error was %s\n",
+                fname, strerror(errno)));
+        close(fd);
+      }
+      else
+        gotlock = True;
+    } while(!gotlock);
+
+    /*
+     * We have to come here if any of the above calls fail
+     * as we don't want to return and leave ourselves running
+     * as root !
+     */
+
+    umask(old_umask);
+  }
+
+  *ptok = (int)fd;
+
+  /* return to our previous privilage level */
+  unbecome_root(False);
+
+  return ret;
+}
+
+/*******************************************************************
+  unlock a share mode file.
+  ******************************************************************/
+static BOOL slow_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
+{
+  int fd = (int)token;
+  int ret = True;
+  struct stat sb;
+  pstring fname;
+
+  /* Fix for zero length share files from
+     Gerald Werner <wernerg@mfldclin.edu> */
+    
+  share_name(cnum, dev, inode, fname);
+
+  /* get the share mode file size */
+  if(fstat((int)token, &sb) != 0)
+  {
+    DEBUG(0,("ERROR: unlock_share_entry: Failed to do stat on share file %s (%s)\n",
+              fname, strerror(errno)));
+    sb.st_size = 1;
+    ret = False;
+  }
+
+  /* If the file was zero length, we must delete before
+     doing the unlock to avoid a race condition (see
+     the code in lock_share_mode_entry for details.
+   */
+
+  /* remove the share file if zero length */    
+  if(sb.st_size == 0)  
+    delete_share_file(cnum, fname);
+
+  /* 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(fd);
+  return ret;
+}
+
+/*******************************************************************
+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 (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 (IVAL(buf,SMF_VERSION_OFFSET) != LOCKING_VERSION) {
+    DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, 
+                    IVAL(buf,SMF_VERSION_OFFSET), LOCKING_VERSION));
+   if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return -1;
+  }
+
+  /* Sanity check for file contents */
+  size = sb.st_size;
+  size -= SMF_HEADER_LENGTH; /* Remove the header */
+
+  /* Remove the filename component. */
+  size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
+
+  /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+  if((size % SMF_ENTRY_LENGTH) != 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;
+  }
+
+  *out = buf;
+  return 0;
+}
+
+/*******************************************************************
+get all share mode entries in a share file for a dev/inode pair.
+********************************************************************/
+static int slow_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, 
+                               share_mode_entry **old_shares)
+{
+  int fd = (int)token;
+  pstring fname;
+  int i;
+  int num_entries;
+  int num_entries_copied;
+  int newsize;
+  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).
+
+   Followed by <n> share mode entries of the form :
+
+     0   -  tv_sec
+     4   -  tv_usec
+     8   -  share_mode
+    12   -  pid
+    16   -  oplock port (if oplocks in use) - 2 bytes.
+  */
+
+  share_name(cnum, dev, inode, fname);
+
+  if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
+  {
+    DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
+                  fname));
+    return 0;
+  }
+
+  if(new_file == True)
+    return 0;
+
+  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+  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));
+    return 0;
+  }
+
+  if(num_entries)
+  {
+    *old_shares = share_array = (share_mode_entry *)
+                 malloc(num_entries * sizeof(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;
+  }
+
+  num_entries_copied = 0;
+  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+  for( i = 0; i < num_entries; i++)
+  {
+    int pid;
+    char *p = base + (i*SMF_ENTRY_LENGTH);
+
+    pid = IVAL(p,SME_PID_OFFSET);
+
+    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,SME_SHAREMODE_OFFSET), fname));
+      continue;
+    }
+    share_array[num_entries_copied].time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+    share_array[num_entries_copied].time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+    share_array[num_entries_copied].share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+    share_array[num_entries_copied].pid = pid;
+    share_array[num_entries_copied].op_port = SVAL(p,SME_PORT_OFFSET);
+    share_array[num_entries_copied].op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+    num_entries_copied++;
+  }
+
+  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);
+    *old_shares = 0;
+    if(buf)
+      free(buf);
+    delete_share_file(cnum, fname);
+    return 0;
+  }
+
+  /* If we deleted some entries we need to re-write the whole number of
+     share mode entries back into the file. */
+
+  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);
+      *old_shares = 0;
+      if(buf)
+        free(buf);
+      return 0;
+    }
+
+    SIVAL(buf, SMF_NUM_ENTRIES_OFFSET, num_entries_copied);
+    for( i = 0; i < num_entries_copied; i++)
+    {
+      char *p = base + (i*SMF_ENTRY_LENGTH);
+
+      SIVAL(p,SME_PID_OFFSET,share_array[i].pid);
+      SIVAL(p,SME_SHAREMODE_OFFSET,share_array[i].share_mode);
+      SIVAL(p,SME_SEC_OFFSET,share_array[i].time.tv_sec);
+      SIVAL(p,SME_USEC_OFFSET,share_array[i].time.tv_usec);
+      SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
+      SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
+    }
+
+    newsize = (base - buf) + (SMF_ENTRY_LENGTH*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);
+      *old_shares = 0;
+      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);
+      *old_shares = 0;
+      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;
+}
+
+/*******************************************************************
+del a share mode from a share mode file.
+********************************************************************/
+static void slow_del_share_mode(int token, int fnum)
+{
+  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;
+  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)
+  {
+    DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
+                  fname));
+    return;
+  }
+
+  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;
+  }
+
+  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+  DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
+            fname, num_entries));
+
+  /* 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));
+    return;
+  }
+
+  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;
+  }
+
+  pid = getpid();
+
+  /* Go through the entries looking for the particular one
+     we have set - delete it.
+  */
+
+  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+  for(i = 0; i < num_entries; i++)
+  {
+    char *p = base + (i*SMF_ENTRY_LENGTH);
+
+    if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) || 
+       (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
+       (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) || 
+       (IVAL(p,SME_PID_OFFSET) != 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 + SMF_ENTRY_LENGTH, (num_entries - i - 1)*SMF_ENTRY_LENGTH);
+
+    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,SMF_NUM_ENTRIES_OFFSET, 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;
+  }
+
+  newsize = (base - buf) + (SMF_ENTRY_LENGTH*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
+********************************************************************/
+static BOOL slow_set_share_mode(int token,int fnum, uint16 port, uint16 op_type)
+{
+  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;
+  }
+
+  /* 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 + SMF_ENTRY_LENGTH)) == NULL)
+    {
+      DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", 
+                  sb.st_size + SMF_ENTRY_LENGTH));
+      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,SMF_VERSION_OFFSET) != LOCKING_VERSION) 
+    {
+      DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,SMF_VERSION_OFFSET), 
+                    LOCKING_VERSION));
+      if(buf)
+        free(buf);
+      delete_share_file(fs_p->cnum, fname);
+      return False;
+    }   
+
+    size -= (SMF_HEADER_LENGTH + SVAL(buf, SMF_FILENAME_LEN_OFFSET)); /* Remove the header */
+
+    /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
+    if((size % SMF_ENTRY_LENGTH) != 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(SMF_HEADER_LENGTH + 
+                  strlen(fs_p->name) + 1 + SMF_ENTRY_LENGTH)) == NULL)
+    {
+      DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
+      return False;
+    }
+    SIVAL(buf,SMF_VERSION_OFFSET,LOCKING_VERSION);
+    SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,0);
+    SSVAL(buf,SMF_FILENAME_LEN_OFFSET,strlen(fs_p->name) + 1);
+    strcpy(buf + SMF_HEADER_LENGTH, fs_p->name);
+  }
+
+  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+  header_size = SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+  p = buf + header_size + (num_entries * SMF_ENTRY_LENGTH);
+  SIVAL(p,SME_SEC_OFFSET,fs_p->open_time.tv_sec);
+  SIVAL(p,SME_USEC_OFFSET,fs_p->open_time.tv_usec);
+  SIVAL(p,SME_SHAREMODE_OFFSET,fs_p->share_mode);
+  SIVAL(p,SME_PID_OFFSET,pid);
+  SSVAL(p,SME_PORT_OFFSET,port);
+  SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
+
+  num_entries++;
+
+  SIVAL(buf,SMF_NUM_ENTRIES_OFFSET,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*SMF_ENTRY_LENGTH)) != 
+                       (header_size + (num_entries*SMF_ENTRY_LENGTH))) 
+  {
+    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 + (SMF_ENTRY_LENGTH*num_entries))!= 0)
+  {
+    DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, header_size + (SMF_ENTRY_LENGTH*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));
+
+  return True;
+}
+
+/*******************************************************************
+Remove an oplock port and mode entry from a share mode.
+********************************************************************/
+static BOOL slow_remove_share_oplock(int fnum, int token)
+{
+  pstring fname;
+  int fd = (int)token;
+  char *buf = 0;
+  char *base = 0;
+  int num_entries;
+  int fsize;
+  int i;
+  files_struct *fs_p = &Files[fnum];
+  int pid;
+  BOOL found = 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)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
+                  fname));
+    return False;
+  }
+
+  if(new_file == True)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
+deleting it.\n", fname));
+    delete_share_file(fs_p->cnum, fname);
+    return False;
+  }
+
+  num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
+
+  DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
+            fname, num_entries));
+
+  /* PARANOIA TEST */
+  if(num_entries < 0)
+  {
+    DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+    return False;
+  }
+
+  if(num_entries == 0)
+  {
+    /* No entries - just delete the file. */
+    DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
+              fname));
+    if(buf)
+      free(buf);
+    delete_share_file(fs_p->cnum, fname);
+    return False;
+  }
+
+  pid = getpid();
+
+  /* Go through the entries looking for the particular one
+     we have set - remove the oplock settings on it.
+  */
+
+  base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
+
+  for(i = 0; i < num_entries; i++)
+  {
+    char *p = base + (i*SMF_ENTRY_LENGTH);
+
+    if((IVAL(p,SME_SEC_OFFSET) != fs_p->open_time.tv_sec) || 
+       (IVAL(p,SME_USEC_OFFSET) != fs_p->open_time.tv_usec) ||
+       (IVAL(p,SME_SHAREMODE_OFFSET) != fs_p->share_mode) || 
+       (IVAL(p,SME_PID_OFFSET) != pid))
+      continue;
+
+    DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
+from the share file %s\n", i, num_entries, fname));
+
+    SSVAL(p,SME_PORT_OFFSET,0);
+    SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
+    found = True;
+    break;
+  }
+
+  if(!found)
+  {
+    DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  /* Re-write the file - and truncate it at the correct point. */
+  if(lseek(fd, 0, SEEK_SET) != 0)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
+  if(write(fd, buf, fsize) != fsize)
+  {
+    DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+    if(buf)
+      free(buf);
+    return False;
+  }
+
+  return True;
+}
+
+
+
+/*******************************************************************
+call the specified function on each entry under management by the
+share ode system
+********************************************************************/
+static int slow_share_forall(void (*fn)(share_mode_entry *, char *))
+{
+       int i, count=0;
+       void *dir;
+       char *s;
+       share_mode_entry e;
+
+       dir = opendir(lp_lockdir());
+       if (!dir) {
+               return(0);
+       }
+
+       while ((s=readdirname(dir))) {
+               char *buf;
+               char *base;
+               int fd;
+               pstring lname;
+               uint32 dev,inode;
+               BOOL new_file;
+               pstring fname;
+
+               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_RDWR,0);
+               if (fd < 0) {
+                       continue;
+               }
+
+               /* Lock the share mode file while we read it. */
+               if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False) {
+                       close(fd);
+                       continue;
+               }
+
+               if(read_share_file( 0, fd, lname, &buf, &new_file)) {
+                       close(fd);
+                       continue;
+               } 
+               strcpy( fname, &buf[10]);
+               close(fd);
+      
+               base = buf + SMF_HEADER_LENGTH + 
+                       SVAL(buf,SMF_FILENAME_LEN_OFFSET); 
+               for( i = 0; i < IVAL(buf, SMF_NUM_ENTRIES_OFFSET); i++) {
+                       char *p = base + (i*SMF_ENTRY_LENGTH);
+                       e.pid = IVAL(p,SME_PID_OFFSET);
+                       e.share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+                       e.time.tv_sec = IVAL(p,SME_SEC_OFFSET);
+                       e.time.tv_usec = IVAL(p,SME_USEC_OFFSET);
+                       e.op_port = SVAL(p,SME_PORT_OFFSET);
+                       e.pid = SVAL(p,SME_PID_OFFSET);
+                       e.op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+
+                       fn(&e, fname);
+                       count++;
+               } /* end for i */
+
+               if(buf)
+                       free(buf);
+               base = 0;
+       } /* end while */
+       closedir(dir);
+
+       return count;
+}
+
+
+/*******************************************************************
+dump the state of the system
+********************************************************************/
+static void slow_share_status(FILE *f)
+{
+       
+}
+
+
+static struct share_ops share_ops = {
+       slow_stop_share_mode_mgmt,
+       slow_lock_share_entry,
+       slow_unlock_share_entry,
+       slow_get_share_modes,
+       slow_del_share_mode,
+       slow_set_share_mode,
+       slow_remove_share_oplock,
+       slow_share_forall,
+       slow_share_status,
+};
+
+/*******************************************************************
+  initialize the slow share_mode management 
+  ******************************************************************/
+struct share_ops *locking_slow_init(void)
+{
+       if (!directory_exist(lp_lockdir(),NULL)) {
+               mkdir(lp_lockdir(),0755);
+               if (!directory_exist(lp_lockdir(),NULL))
+                       return NULL;
+       }
+
+       return &share_ops;
+}
index c5b7c500719291b090adc32888998b949932f2fd..7576ee323b0dadc1ad305cfba42d17728e444d31 100644 (file)
@@ -3422,7 +3422,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
      (num_ulocks == 0) && (num_locks == 0) &&
      (CVAL(inbuf,smb_vwv0) == 0xFF))
   {
-    share_lock_token token;
+    int token;
     files_struct *fsp = &Files[fnum];
     uint32 dev = fsp->fd_ptr->dev;
     uint32 inode = fsp->fd_ptr->inode;
index be24ad7781a309a131ba5971f0e122063ca21d20..7d9638f01e86267ecd8cb15d0c559792a1cf7db1 100644 (file)
@@ -1373,7 +1373,7 @@ void close_file(int fnum, BOOL normal_close)
   int cnum = fs_p->cnum;
   uint32 dev = fs_p->fd_ptr->dev;
   uint32 inode = fs_p->fd_ptr->inode;
-  share_lock_token token;
+  int token;
 
   invalidate_read_prediction(fs_p->fd_ptr->fd);
   fs_p->open = False;
@@ -1477,10 +1477,10 @@ BOOL check_file_sharing(int cnum,char *fname)
 {
   int i;
   int ret = False;
-  min_share_mode_entry *old_shares = 0;
+  share_mode_entry *old_shares = 0;
   int num_share_modes;
   struct stat sbuf;
-  share_lock_token token;
+  int token;
   int pid = getpid();
   uint32 dev, inode;
 
@@ -1509,7 +1509,7 @@ BOOL check_file_sharing(int cnum,char *fname)
       broke_oplock = False;
       for(i = 0; i < num_share_modes; i++)
       {
-        min_share_mode_entry *share_entry = &old_shares[i];
+        share_mode_entry *share_entry = &old_shares[i];
 
         /* 
          * Break oplocks before checking share modes. See comment in
@@ -1571,8 +1571,8 @@ free_and_exit:
   Helper for open_file_shared. 
   Truncate a file after checking locking; close file if locked.
   **************************************************************************/
-static void truncate_unless_locked(int fnum, int cnum, share_lock_token token, 
-       BOOL *share_locked)
+static void truncate_unless_locked(int fnum, int cnum, int token, 
+                                  BOOL *share_locked)
 {
   if (Files[fnum].can_write){
     if (is_locked(fnum,cnum,0x3FFFFFFF,0)){
@@ -1596,7 +1596,7 @@ static void truncate_unless_locked(int fnum, int cnum, share_lock_token token,
 /****************************************************************************
 check if we can open a file with a share mode
 ****************************************************************************/
-int check_share_mode( min_share_mode_entry *share, int deny_mode, char *fname,
+int check_share_mode( share_mode_entry *share, int deny_mode, char *fname,
                       BOOL fcbopen, int *flags)
 {
   int old_open_mode = share->share_mode &0xF;
@@ -1648,7 +1648,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   BOOL file_existed = file_exist(fname,&sbuf);
   BOOL share_locked = False;
   BOOL fcbopen = False;
-  share_lock_token token;
+  int token;
   uint32 dev = 0;
   uint32 inode = 0;
   int num_share_modes = 0;
@@ -1724,7 +1724,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
   if (lp_share_modes(SNUM(cnum))) 
   {
     int i;
-    min_share_mode_entry *old_shares = 0;
+    share_mode_entry *old_shares = 0;
 
     if (file_existed)
     {
@@ -1749,7 +1749,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun,
         broke_oplock = False;
         for(i = 0; i < num_share_modes; i++)
         {
-          min_share_mode_entry *share_entry = &old_shares[i];
+          share_mode_entry *share_entry = &old_shares[i];
 
           /* 
            * By observation of NetBench, oplocks are broken *before* share
@@ -2794,7 +2794,7 @@ Send an oplock break message to another smbd process. If the oplock is held
 by the local smbd then call the oplock break function directly.
 ****************************************************************************/
 
-BOOL request_oplock_break(min_share_mode_entry *share_entry, 
+BOOL request_oplock_break(share_mode_entry *share_entry, 
                           uint32 dev, uint32 inode)
 {
   char op_break_msg[OPLOCK_BREAK_MSG_LEN];
@@ -4177,9 +4177,7 @@ void exit_server(char *reason)
 #endif
   }    
 
-#ifdef FAST_SHARE_MODES
-  stop_share_mode_mgmt();
-#endif /* FAST_SHARE_MODES */
+  locking_end();
 
   DEBUG(3,("%s Server exit  (%s)\n",timestring(),reason?reason:""));
   exit(0);
@@ -5012,10 +5010,8 @@ static void usage(char *pname)
   if (!open_sockets(is_daemon,port))
     exit(1);
 
-#ifdef FAST_SHARE_MODES
-  if (!start_share_mode_mgmt())
+  if (!locking_init())
     exit(1);
-#endif /* FAST_SHARE_MODES */
 
   /* possibly reload the services file. */
   reload_services(True);
index 4143244ab4dcb98e90a03a1645b9b6c12edf9788..3e349f920a2c0be1c7a8400ee226b76a692d04b4 100644 (file)
@@ -53,80 +53,52 @@ 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;
-  }
+/* we need these because we link to locking*.o */
+ void become_root(BOOL save_dir) {}
+ void unbecome_root(BOOL restore_dir) {}
+connection_struct Connections[MAX_CONNECTIONS];
+files_struct Files[MAX_OPEN_FILES];
 
-  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,SMF_VERSION_OFFSET) != 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,SMF_VERSION_OFFSET), LOCKING_VERSION);
-    if(buf)
-      free(buf);
-    return 0;
-  }
+static void print_share_mode(share_mode_entry *e, char *fname)
+{
+       static int count;
+       if (count==0) {
+               printf("Locked files:\n");
+               printf("Pid    DenyMode   R/W        Oplock           Name\n");
+               printf("--------------------------------------------------\n");
+       }
+       count++;
+
+       printf("%-5d  ",e->pid);
+       switch ((e->share_mode>>4)&0xF) {
+       case DENY_NONE: printf("DENY_NONE  "); break;
+       case DENY_ALL:  printf("DENY_ALL   "); break;
+       case DENY_DOS:  printf("DENY_DOS   "); break;
+       case DENY_READ: printf("DENY_READ  "); break;
+       case DENY_WRITE:printf("DENY_WRITE "); break;
+       }
+       switch (e->share_mode&0xF) {
+       case 0: printf("RDONLY     "); break;
+       case 1: printf("WRONLY     "); break;
+       case 2: printf("RDWR       "); break;
+       }
+
+       if((e->op_type & 
+           (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == 
+          (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+               printf("EXCLUSIVE+BATCH ");
+       else if (e->op_type & EXCLUSIVE_OPLOCK)
+               printf("EXCLUSIVE       ");
+       else if (e->op_type & BATCH_OPLOCK)
+               printf("BATCH           ");
+       else
+               printf("NONE            ");
+
+       printf(" %s   %s",fname,asctime(LocalTime((time_t *)&e->time.tv_sec)));
+}
 
-  /* Sanity check for file contents */
-  size = sb.st_size;
-  size -= SMF_HEADER_LENGTH; /* Remove the header */
 
-  /* Remove the filename component. */
-  size -= SVAL(buf, SMF_FILENAME_LEN_OFFSET);
-
-  /* The remaining size must be a multiple of SMF_ENTRY_LENGTH - error if not. */
-  if((size % SMF_ENTRY_LENGTH) != 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[])
 {
@@ -136,20 +108,8 @@ locking version (was %d, should be %d).\n",fname,
   static pstring servicesf = CONFIGFILE;
   extern char *optarg;
   int verbose = 0, brief =0;
-  BOOL firstopen=True;
   BOOL processes_only=False;
   int last_pid=0;
-#ifdef FAST_SHARE_MODES
-  pstring shmem_file_name;
-  share_mode_record *file_scanner_p;
-  smb_shm_offset_t *mode_array;
-  int bytes_free, bytes_used, bytes_overhead, bytes_total;
-#else /* FAST_SHARE_MODES */
-  void *dir;
-  char *s;
-#endif /* FAST_SHARE_MODES */
-  int oplock_type;
-  int i;
   struct session_record *ptr;
 
 
@@ -302,191 +262,16 @@ locking version (was %d, should be %d).\n",fname,
 
   printf("\n");
 
-#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, lp_shmem_size())) exit(-1);
-  
-  mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
-  if(mode_array == NULL)
-  {
-    printf("%s: base of shared memory hash array == 0! Exiting.\n", argv[0]);
-    smb_shm_close();
-    exit(-1);
-  }
-
-  for( i = 0; i < lp_shmem_hash_size(); i++)
-  {
-    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;
-     
-        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);
-        oplock_type = entry_scanner_p->op_type;
-
-#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) 
-     {
-       printf("%s: Unable to open lock directory %s.\n", argv[0], lp_lockdir());
-       return(0);
-     }
-     while ((s=readdirname(dir))) {
-       char *buf;
-       char *base;
-       int fd;
-       pstring lname;
-       uint32 dev,inode;
-       
-       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_RDWR,0);
-       if (fd < 0) 
-       {
-         printf("%s: Unable to open share file %s.\n", argv[0], lname);
-         continue;
-       }
-
-       /* 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 + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET); 
-       for( i = 0; i < IVAL(buf, SMF_NUM_ENTRIES_OFFSET); i++)
-       {
-         char *p = base + (i*SMF_ENTRY_LENGTH);
-         struct timeval t;
-         int pid = IVAL(p,SME_PID_OFFSET);
-         int mode = IVAL(p,SME_SHAREMODE_OFFSET);
-     
-         t.tv_sec = IVAL(p,SME_SEC_OFFSET);
-         t.tv_usec = IVAL(p,SME_USEC_OFFSET);
-         oplock_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
-#endif /* FAST_SHARE_MODES */
-
-    fname[sizeof(fname)-1] = 0;
-
-    if (firstopen) {
-      firstopen=False;
-      printf("Locked files:\n");
-      printf("Pid    DenyMode   R/W        Oplock           Name\n");
-      printf("--------------------------------------------------\n");
-    }
-
-
-    printf("%-5d  ",pid);
-    switch ((mode>>4)&0xF)
-      {
-      case DENY_NONE: printf("DENY_NONE  "); break;
-      case DENY_ALL:  printf("DENY_ALL   "); break;
-      case DENY_DOS:  printf("DENY_DOS   "); break;
-      case DENY_READ: printf("DENY_READ  "); break;
-      case DENY_WRITE:printf("DENY_WRITE "); break;
-      }
-    switch (mode&0xF) 
-      {
-      case 0: printf("RDONLY     "); break;
-      case 1: printf("WRONLY     "); break;
-      case 2: printf("RDWR       "); break;
-      }
-
-    if((oplock_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
-      printf("EXCLUSIVE+BATCH ");
-    else if (oplock_type & EXCLUSIVE_OPLOCK)
-      printf("EXCLUSIVE       ");
-    else if (oplock_type & BATCH_OPLOCK)
-      printf("BATCH           ");
-    else
-      printf("NONE            ");
-
-    printf(" %s   %s",fname,asctime(LocalTime((time_t *)&t.tv_sec)));
-
-#ifdef FAST_SHARE_MODES
+  locking_init();
 
-        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;
-
-  /*******************************************************************
-  deinitialize the shared memory for share_mode management 
-  ******************************************************************/
-  smb_shm_close();
+  if (share_mode_forall(print_share_mode) <= 0)
+    printf("No locked files\n");
 
-#else /* FAST_SHARE_MODES */
-    } /* end for i */
+  printf("\n");
 
-    if(buf)
-      free(buf);
-    base = 0;
-  } /* end while */
-  closedir(dir);
+  share_status(stdout);
 
-#endif /* FAST_SHARE_MODES */
-  if (firstopen)
-    printf("No locked files\n");
-#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,
-        bytes_used, (bytes_used * 100)/bytes_total,
-        bytes_overhead, (bytes_overhead * 100)/bytes_total,
-        bytes_total);
-  
-#endif /* FAST_SHARE_MODES */
+  locking_end();
 
   return (0);
 }