first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[jra/samba/.git] / source3 / locking / locking.c
index 834f3e565895c4266e8e5f4e65f588b2d9e1fa12..012d954e501533402bc5b53c350bb8a2d7d29590 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Locking functions
-   Copyright (C) Andrew Tridgell 1992-1997
+   Copyright (C) Andrew Tridgell 1992-1998
    
    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
 
    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.
+
 */
 
 #include "includes.h"
 extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
+
+static struct share_ops *share_ops;
+
+/****************************************************************************
+ Utility function to map a lock type correctly depending on the real open
+ mode of a file.
+****************************************************************************/
+
+static int map_lock_type( files_struct *fsp, int lock_type)
+{
+  if((lock_type == F_WRLCK) && (fsp->fd_ptr->real_open_flags == O_RDONLY)) {
+    /*
+     * Many UNIX's cannot get a write lock on a file opened read-only.
+     * Win32 locking semantics allow this.
+     * Do the best we can and attempt a read-only lock.
+     */
+    DEBUG(10,("map_lock_type: Downgrading write lock to read due to read-only file.\n"));
+    return F_RDLCK;
+  } else if( (lock_type == F_RDLCK) && (fsp->fd_ptr->real_open_flags == O_WRONLY)) {
+    /*
+     * Ditto for read locks on write only files.
+     */
+    DEBUG(10,("map_lock_type: Changing read lock to write due to write-only file.\n"));
+    return F_WRLCK;
+  }
+
+  /*
+   * This return should be the most normal, as we attempt
+   * to always open files read/write.
+   */
+
+  return lock_type;
+}
 
 /****************************************************************************
-  utility function called to see if a file region is locked
+ Utility function called to see if a file region is locked.
 ****************************************************************************/
-BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
+BOOL is_locked(files_struct *fsp,connection_struct *conn,
+              SMB_OFF_T count,SMB_OFF_T offset, int lock_type)
 {
-  int snum = SNUM(cnum);
+       int snum = SNUM(conn);
 
-  if (count == 0)
-    return(False);
+       if (count == 0)
+               return(False);
 
-  if (!lp_locking(snum) || !lp_strict_locking(snum))
-    return(False);
+       if (!lp_locking(snum) || !lp_strict_locking(snum))
+               return(False);
 
-  return(fcntl_lock(Files[fnum].fd_ptr->fd,F_GETLK,offset,count,
-                   (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
+       /*
+        * Note that most UNIX's can *test* for a write lock on
+        * a read-only fd, just not *set* a write lock on a read-only
+        * fd. So we don't need to use map_lock_type here.
+        */
+       
+       return(fcntl_lock(fsp->fd_ptr->fd,SMB_F_GETLK,offset,count,lock_type));
 }
 
 
 /****************************************************************************
-  utility function called by locking requests
+ Utility function called by locking requests.
 ****************************************************************************/
-BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+BOOL do_lock(files_struct *fsp,connection_struct *conn,
+             SMB_OFF_T count,SMB_OFF_T offset,int lock_type,
+             int *eclass,uint32 *ecode)
 {
   BOOL ok = False;
 
-  if (!lp_locking(SNUM(cnum)))
+  if (!lp_locking(SNUM(conn)))
     return(True);
 
   if (count == 0) {
@@ -66,9 +109,12 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
     return False;
   }
 
-  if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
-    ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,
-                    (Files[fnum].can_write?F_WRLCK:F_RDLCK));
+  DEBUG(10,("do_lock: lock type %d start=%.0f len=%.0f requested for file %s\n",
+        lock_type, (double)offset, (double)count, fsp->fsp_name ));
+
+  if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
+    ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,
+                    map_lock_type(fsp,lock_type));
 
   if (!ok) {
     *eclass = ERRDOS;
@@ -80,17 +126,21 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec
 
 
 /****************************************************************************
-  utility function called by unlocking requests
+ Utility function called by unlocking requests.
 ****************************************************************************/
-BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+BOOL do_unlock(files_struct *fsp,connection_struct *conn,
+               SMB_OFF_T count,SMB_OFF_T offset,int *eclass,uint32 *ecode)
 {
   BOOL ok = False;
 
-  if (!lp_locking(SNUM(cnum)))
+  if (!lp_locking(SNUM(conn)))
     return(True);
 
-  if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
-    ok = fcntl_lock(Files[fnum].fd_ptr->fd,F_SETLK,offset,count,F_UNLCK);
+  DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
+        (double)offset, (double)count, fsp->fsp_name ));
+
+  if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
+    ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,F_UNLCK);
    
   if (!ok) {
     *eclass = ERRDOS;
@@ -100,1415 +150,191 @@ 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)
+/****************************************************************************
+ Initialise the locking functions.
+****************************************************************************/
+
+BOOL locking_init(int read_only)
 {
-   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());
-}
+       if (share_ops)
+               return True;
 
+#ifdef FAST_SHARE_MODES
+       share_ops = locking_shm_init(read_only);
+       if (!share_ops && read_only && (getuid() == 0)) {
+               /* this may be the first time the share modes code has
+                   been run. Initialise it now by running it read-write */
+               share_ops = locking_shm_init(0);
+       }
+#else
+       share_ops = locking_slow_init(read_only);
+#endif
+
+       if (!share_ops) {
+               DEBUG(0,("ERROR: Failed to initialise share modes\n"));
+               return False;
+       }
+       
+       return True;
+}
 
 /*******************************************************************
-  deinitialize the shared memory for share_mode management 
-  ******************************************************************/
-BOOL stop_share_mode_mgmt(void)
+ Deinitialize the share_mode management.
+******************************************************************/
+
+BOOL locking_end(void)
 {
-   return smb_shm_close();
+       if (share_ops)
+               return share_ops->stop_mgmt();
+       return True;
 }
 
+
 /*******************************************************************
-  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)
+ Lock a hash bucket entry.
+******************************************************************/
+BOOL lock_share_entry(connection_struct *conn,
+                     SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
 {
-  return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
+       return share_ops->lock_entry(conn, dev, inode, ptok);
 }
 
 /*******************************************************************
-  unlock a hash bucket entry in shared memory for share_mode management 
-  ******************************************************************/
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+ Unlock a hash bucket entry.
+******************************************************************/
+BOOL unlock_share_entry(connection_struct *conn,
+                       SMB_DEV_T dev, SMB_INO_T inode, int token)
 {
-  return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
+       return share_ops->unlock_entry(conn, dev, inode, token);
 }
 
 /*******************************************************************
-get all share mode entries in shared memory for a dev/inode pair.
+ Get all share mode entries for a dev/inode pair.
 ********************************************************************/
-int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
-                    min_share_mode_entry **old_shares)
+int get_share_modes(connection_struct *conn, 
+                   int token, SMB_DEV_T dev, SMB_INO_T inode, 
+                   share_mode_entry **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;
-
-      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, entry_scanner_p->share_mode, dev, inode, hash_entry,
-            file_scanner_p->num_share_mode_entries));
-
-      smb_shm_free(smb_shm_addr2offset(delete_entry_p));
-    } 
-    else
-    {
-       /* This is a valid share mode entry and the process that
-           created it still exists. Copy it into the output array.
-       */
-       share_array[num_entries_copied].pid = entry_scanner_p->pid;
-       share_array[num_entries_copied].share_mode = entry_scanner_p->share_mode;
-#ifdef USE_OPLOCKS
-       share_array[num_entries_copied].op_port = entry_scanner_p->op_port;
-       share_array[num_entries_copied].op_type = entry_scanner_p->op_type;
-#endif /* USE_OPLOCKS */
-       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);
-}  
+       return share_ops->get_entries(conn, token, dev, inode, shares);
+}
 
 /*******************************************************************
-del the share mode of a file.
+ Del the share mode of a file.
 ********************************************************************/
-void del_share_mode(share_lock_token token, int fnum)
+void del_share_mode(int token, files_struct *fsp)
 {
-  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));
-  }
+       share_ops->del_entry(token, fsp);
 }
 
 /*******************************************************************
-set the share mode of a file. Return False on fail, True on success.
+ 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)
+BOOL set_share_mode(int token, files_struct *fsp, 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;
-#ifdef USE_OPLOCKS
-  new_entry_p->op_port = port;
-  new_entry_p->op_type = op_type;
-#endif /* USE_OPLOCKS */
-  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);
+       return share_ops->set_entry(token, fsp, port, op_type);
 }
 
 /*******************************************************************
-Remove an oplock port and mode entry from a share mode.
+ Static function that actually does the work for the generic function
+ below.
 ********************************************************************/
-BOOL remove_share_oplock(int fnum, share_lock_token token)
-{
-#ifdef USE_OPLOCKS
-  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->op_port != 0) &&
-        (entry_scanner_p->op_type != 0) && 
-        (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 /* USE_OPLOCKS */
-  return False;
-#endif /* USE_OPLOCKS */
-}
-
-#else /* FAST_SHARE_MODES */
-
-/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
-
-/*******************************************************************
-  name a share file
-  ******************************************************************/
-static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
+static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
+                                   void *param)
 {
-  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);
+  DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
+        (unsigned int)dev, (double)inode ));
+  /* Delete the oplock info. */
+  entry->op_port = 0;
+  entry->op_type = NO_OPLOCK;
 }
 
 /*******************************************************************
-  lock a share mode file.
-  ******************************************************************/
-BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
-{
-  pstring fname;
-  int fd;
-
-  *ptok = (share_lock_token)-1;
-
-  if(!share_name(cnum, dev, inode, fname))
-    return False;
-
-  {
-    int old_umask;
-    unbecome_user();
-    old_umask = umask(0);
-#ifdef SECURE_SHARE_MODES
-    fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0600);
-#else /* SECURE_SHARE_MODES */
-    fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0666);
-#endif /* SECURE_SHARE_MODES */
-    umask(old_umask);
-    if(!become_user(cnum,Connections[cnum].vuid))
-    {
-      DEBUG(0,("lock_share_entry: Can't become connected user!\n"));
-      close(fd);
-      return False;
-    }
-    /* We need to change directory back to the connection root. */
-    if (ChDir(Connections[cnum].connectpath) != 0)
-    {
-      DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n",
-              Connections[cnum].connectpath, strerror(errno)));
-      close(fd);
-      return False;  
-    }
-  }
-
-  /* At this point we have an open fd to the share mode file. 
-     Lock the first byte exclusively to signify a lock. */
-  if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
-   {
-      DEBUG(0,("ERROR lock_share_entry: fcntl_lock failed with %s\n",
-                  strerror(errno)));   
-      close(fd);
-      return False;
-   }
-
-   *ptok = (share_lock_token)fd;
-   return True;
-}
+ Remove an oplock port and mode entry from a share mode.
+********************************************************************/
 
-/*******************************************************************
-  unlock a share mode file.
-  ******************************************************************/
-BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+BOOL remove_share_oplock(int token, files_struct *fsp)
 {
-  int fd = (int)token;
-  int ret = True;
-
-  /* token is the fd of the open share mode file. */
-  /* Unlock the first byte. */
-  if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
-   { 
-      DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
-                      strerror(errno)));   
-      ret = False;
-   }
-  close((int)token);
-  return ret;
+       return share_ops->mod_entry(token, fsp, remove_share_oplock_fn, NULL);
 }
 
 /*******************************************************************
-Force a share file to be deleted.
+ Static function that actually does the work for the generic function
+ below.
 ********************************************************************/
 
-static int delete_share_file( int cnum, char *fname )
+static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
+                                   void *param)
 {
-  unbecome_user();
-  if(unlink(fname) != 0)
-  {
-    DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
-            fname, strerror(errno)));
-  }
-
-  DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
-
-  if(!become_user(cnum,Connections[cnum].vuid))
-  {
-    DEBUG(0,("delete_share_file: Can't become connected user!\n"));
-    return -1;
-  }
-  /* We need to change directory back to the connection root. */
-  if (ChDir(Connections[cnum].connectpath) != 0)
-  {
-    DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n",
-            Connections[cnum].connectpath, strerror(errno)));
-    return -1;  
-  }
-  return 0;
+  DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
+        (unsigned int)dev, (double)inode ));
+  entry->op_type = LEVEL_II_OPLOCK;
 }
 
 /*******************************************************************
-Read a share file into a buffer.
+ Downgrade a oplock type from exclusive to level II.
 ********************************************************************/
 
-static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
+BOOL downgrade_share_oplock(int token, files_struct *fsp)
 {
-  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;
+    return share_ops->mod_entry(token, fsp, downgrade_share_oplock_fn, NULL);
 }
 
 /*******************************************************************
-get all share mode entries in a share file for a dev/inode pair.
+ Static function that actually does the work for the generic function
+ below.
 ********************************************************************/
-int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, 
-                    min_share_mode_entry **old_shares)
-{
-  int fd = (int)token;
-  pstring fname;
-  int 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 :
+struct mod_val {
+       int new_share_mode;
+       uint16 new_oplock;
+};
 
-     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;
-#ifdef USE_OPLOCKS
-    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);
-#endif /* USE_OPLOCKS */
-
-    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);
-#ifdef USE_OPLOCKS
-      SSVAL(p,SME_PORT_OFFSET,share_array[i].op_port);
-      SSVAL(p,SME_OPLOCK_TYPE_OFFSET,share_array[i].op_type);
-#endif /* USE_OPLOCKS */
-    }
-
-    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;
+static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
+                                   void *param)
+{
+       struct mod_val *mvp = (struct mod_val *)param;
+
+       DEBUG(10,("modify_share_mode_fn: changing share mode info from %x to %x for entry dev=%x ino=%.0f\n",
+        entry->share_mode, mvp->new_share_mode, (unsigned int)dev, (double)inode ));
+       DEBUG(10,("modify_share_mode_fn: changing oplock state from %x to %x for entry dev=%x ino=%.0f\n",
+        entry->op_type, (int)mvp->new_oplock, (unsigned int)dev, (double)inode ));
+       /* Change the share mode info. */
+       entry->share_mode = mvp->new_share_mode;
+       entry->op_type = mvp->new_oplock;
 }
 
 /*******************************************************************
-del a share mode from a share mode file.
+ Modify a share mode on a file. Used by the delete open file code.
+ Return False on fail, True on success.
 ********************************************************************/
-void del_share_mode(share_lock_token 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;
-  }
+BOOL modify_share_mode(int token, files_struct *fsp, int new_mode, uint16 new_oplock)
+{
+       struct mod_val mv;
 
-  /* 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;
-  }
+       mv.new_share_mode = new_mode;
+    mv.new_oplock = new_oplock;
 
-  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;
-  }
+       return share_ops->mod_entry(token, fsp, modify_share_mode_fn, (void *)&mv);
 }
-  
+
 /*******************************************************************
-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)
-{
-  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);
-#ifdef USE_OPLOCKS
-  SSVAL(p,SME_PORT_OFFSET,port);
-  SSVAL(p,SME_OPLOCK_TYPE_OFFSET,op_type);
-#endif /* USE_OPLOCKS */
-
-  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;
+int share_mode_forall(void (*fn)(share_mode_entry *, char *))
+{
+       if (!share_ops) return 0;
+       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)
-{
-#ifdef USE_OPLOCKS
-  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) ||
-       (SVAL(p,SME_PORT_OFFSET) == 0) ||
-       (SVAL(p,SME_OPLOCK_TYPE_OFFSET) == 0))
-      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;
-
-#else /* USE_OPLOCKS */
-  return False;
-#endif /* USE_OPLOCKS */
+void share_status(FILE *f)
+{
+       share_ops->status(f);
 }
-#endif /* FAST_SHARE_MODES */