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 04f4a4b1975a859376f313ae1ab5381342bbd41d..012d954e501533402bc5b53c350bb8a2d7d29590 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Locking functions
-   Copyright (C) Andrew Tridgell 1992-1996
+   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
 
    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.
+
 */
 
 #include "includes.h"
 extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
-
-pstring share_del_pending="";
 
+static struct share_ops *share_ops;
 
 /****************************************************************************
-routine to do file locking
+ Utility function to map a lock type correctly depending on the real open
+ mode of a file.
 ****************************************************************************/
-BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
-{
-#if HAVE_FCNTL_LOCK
-  struct flock lock;
-  int ret;
-
-#if 1
-  uint32 mask = 0xC0000000;
-
-  /* make sure the count is reasonable, we might kill the lockd otherwise */
-  count &= ~mask;
-
-  /* the offset is often strange - remove 2 of its bits if either of
-     the top two bits are set. Shift the top ones by two bits. This
-     still allows OLE2 apps to operate, but should stop lockd from
-     dieing */
-  if ((offset & mask) != 0)
-    offset = (offset & ~mask) | ((offset & mask) >> 2);
-#else
-  uint32 mask = ((unsigned)1<<31);
-
-  /* interpret negative counts as large numbers */
-  if (count < 0)
-    count &= ~mask;
-
-  /* no negative offsets */
-  offset &= ~mask;
-
-  /* count + offset must be in range */
-  while ((offset < 0 || (offset + count < 0)) && mask)
-    {
-      offset &= ~mask;
-      mask = mask >> 1;
-    }
-#endif
-
-
-  DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
-
-  lock.l_type = type;
-  lock.l_whence = SEEK_SET;
-  lock.l_start = (int)offset;
-  lock.l_len = (int)count;
-  lock.l_pid = 0;
-
-  errno = 0;
-
-  ret = fcntl(fd,op,&lock);
-
-  if (errno != 0)
-    DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
 
-  /* a lock query */
-  if (op == F_GETLK)
-    {
-      if ((ret != -1) &&
-         (lock.l_type != F_UNLCK) && 
-         (lock.l_pid != 0) && 
-         (lock.l_pid != getpid()))
-       {
-         DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
-         return(True);
-       }
-
-      /* it must be not locked or locked by me */
-      return(False);
-    }
-
-  /* a lock set or unset */
-  if (ret == -1)
-    {
-      DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
-              offset,count,op,type,strerror(errno)));
-
-      /* perhaps it doesn't support this sort of locking?? */
-      if (errno == EINVAL)
-       {
-         DEBUG(3,("locking not supported? returning True\n"));
-         return(True);
-       }
-
-      return(False);
-    }
-
-  /* everything went OK */
-  DEBUG(5,("Lock call successful\n"));
-
-  return(True);
-#else
-  return(False);
-#endif
-}
-
-/*******************************************************************
-lock a file - returning a open file descriptor or -1 on failure
-The timeout is in seconds. 0 means no timeout
-********************************************************************/
-int file_lock(char *name,int timeout)
-{  
-  int fd = open(name,O_RDWR|O_CREAT,0666);
-  time_t t=0;
-  if (fd < 0) return(-1);
-
-#if HAVE_FCNTL_LOCK
-  if (timeout) t = time(NULL);
-  while (!timeout || (time(NULL)-t < timeout)) {
-    if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);    
-    msleep(LOCK_RETRY_TIMEOUT);
+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;
   }
-  return(-1);
-#else
-  return(fd);
-#endif
-}
 
-/*******************************************************************
-unlock a file locked by file_lock
-********************************************************************/
-void file_unlock(int fd)
-{
-  if (fd<0) return;
-#if HAVE_FCNTL_LOCK
-  fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
-#endif
-  close(fd);
-}
+  /*
+   * 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,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) {
@@ -197,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,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;
@@ -211,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,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;
@@ -231,476 +150,191 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
   return True; /* Did unlock */
 }
 
-#if 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;
-   
-  strcpy(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 shm_open(shmem_file_name, 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 shm_close();
+       if (share_ops)
+               return share_ops->stop_mgmt();
+       return True;
 }
 
-#else
-
-/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
 
 /*******************************************************************
-  name a share file
-  ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
+ Lock a hash bucket entry.
+******************************************************************/
+BOOL lock_share_entry(connection_struct *conn,
+                     SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
 {
-  strcpy(name,lp_lockdir());
-  standard_sub(cnum,name);
-  trim_string(name,"","/");
-  if (!*name) return(False);
-  name += strlen(name);
-  
-  sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
-  return(True);
+       return share_ops->lock_entry(conn, dev, inode, ptok);
 }
 
 /*******************************************************************
-  use the fnum to get the share file name
-  ******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+ Unlock a hash bucket entry.
+******************************************************************/
+BOOL unlock_share_entry(connection_struct *conn,
+                       SMB_DEV_T dev, SMB_INO_T inode, int token)
 {
-  struct stat st;
-  if (fstat(Files[fnum].fd,&st) != 0) return(False);
-  return(share_name(Files[fnum].cnum,&st,name));
+       return share_ops->unlock_entry(conn, dev, inode, token);
 }
 
-#endif
-
 /*******************************************************************
-  get the share mode of a file using the fnum
-  ******************************************************************/
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+ Get all share mode entries for a dev/inode pair.
+********************************************************************/
+int get_share_modes(connection_struct *conn, 
+                   int token, SMB_DEV_T dev, SMB_INO_T inode, 
+                   share_mode_entry **shares)
 {
-  struct stat sbuf;
-  if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
-  return(get_share_mode(cnum,&sbuf,pid));
+       return share_ops->get_entries(conn, token, dev, inode, shares);
 }
 
 /*******************************************************************
-  get the share mode of a file using the files name
-  ******************************************************************/
-int get_share_mode_byname(int cnum,char *fname,int *pid)
+ Del the share mode of a file.
+********************************************************************/
+void del_share_mode(int token, files_struct *fsp)
 {
-  struct stat sbuf;
-  if (stat(fname,&sbuf) == -1) return(0);
-  return(get_share_mode(cnum,&sbuf,pid));
-}  
-
+       share_ops->del_entry(token, fsp);
+}
 
 /*******************************************************************
-get the share mode of a file
+ Set the share mode of a file. Return False on fail, True on success.
 ********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
 {
-#if FAST_SHARE_MODES
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
-  int ret;
-  BOOL found = False;
-
-  *pid = 0;
-
-  if(!shm_lock()) return (0);
-
-  scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
-  {
-     if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) )
-     {
-       found = True;
-       break;
-     }
-     else
-     {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
-     }
-  }
-  
-  if(!found)
-  {
-     shm_unlock();
-     return (0);
-  }
-  
-  if(scanner_p->locking_version != LOCKING_VERSION)
-  {
-     DEBUG(2,("Deleting old share mode record due to old locking version %d",scanner_p->locking_version));
-     if(prev_p == scanner_p)
-       shm_set_userdef_off(scanner_p->next_offset);
-     else
-       prev_p->next_offset = scanner_p->next_offset;
-     shm_free(shm_addr2offset(scanner_p));
-     *pid = 0;
-       
-     shm_unlock();
-     return (0);
-  }
-  
-  *pid = scanner_p->pid;
-  ret = scanner_p->share_mode;
-
-  if (*pid && !process_exists(*pid))
-  {
-    ret = 0;
-    *pid = 0;
-  }
-  
-  if (! *pid)
-  {
-     if(prev_p == scanner_p)
-       shm_set_userdef_off(scanner_p->next_offset);
-     else
-       prev_p->next_offset = scanner_p->next_offset;
-     shm_free(shm_addr2offset(scanner_p));
-  }
-  
-  if (*pid)
-    DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid));
-
-  if(!shm_unlock()) return (0);
-  
-  return(ret);
-  
-#else
-  pstring fname;
-  int fd2;
-  char buf[16];
-  int ret;
-  time_t t;
-
-  *pid = 0;
-
-  if (!share_name(cnum,sbuf,fname)) return(0);
-
-  fd2 = open(fname,O_RDONLY,0);
-  if (fd2 < 0) return(0);
-
-  if (read(fd2,buf,16) != 16) {
-    close(fd2);
-    unlink(fname);
-    return(0);
-  }
-  close(fd2);
-
-  t = IVAL(buf,0);
-  ret = IVAL(buf,4);
-  *pid = IVAL(buf,8);
-  
-  if (IVAL(buf,12) != LOCKING_VERSION) {    
-    if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
-    *pid = 0;
-    return(0);
-  }
-
-  if (*pid && !process_exists(*pid)) {
-    ret=0;
-    *pid = 0;
-  }
-
-  if (! *pid) unlink(fname); /* XXXXX race, race */
-
-  if (*pid)
-    DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
-
-  return(ret);
-#endif
+       return share_ops->set_entry(token, fsp, port, op_type);
 }
 
-
 /*******************************************************************
-del the share mode of a file, if we set it last
+ Static function that actually does the work for the generic function
+ below.
 ********************************************************************/
-void del_share_mode(int fnum)
-{
-#if FAST_SHARE_MODES
-  struct stat st;
-  time_t t=0;
-  int pid=0;
-  BOOL del = False;
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
-  BOOL found = False;
-
-  
-  
-  if (fstat(Files[fnum].fd,&st) != 0) return;
-  
-  if (!shm_lock()) return;
-  
-  scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
-  {
-     if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
-     {
-       found = True;
-       break;
-     }
-     else
-     {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
-     }
-  }
-    
-  if(!found)
-  {
-     shm_unlock();
-     return;
-  }
-  
-  t = scanner_p->time;
-  pid = scanner_p->pid;
-  
-  if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
-    del = True;
-
-  if (!del && t == Files[fnum].open_time && pid==(int)getpid())
-    del = True;
-
-  if (del)
-  {
-     DEBUG(2,("Deleting share mode record\n"));
-     if(prev_p == scanner_p)
-       shm_set_userdef_off(scanner_p->next_offset);
-     else
-       prev_p->next_offset = scanner_p->next_offset;
-     shm_free(shm_addr2offset(scanner_p));
-       
-  }
 
-  shm_unlock();
-  return;
+static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
+                                   void *param)
+{
+  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;
+}
 
-#else
-  pstring fname;
-  int fd2;
-  char buf[16];
-  time_t t=0;
-  int pid=0;
-  BOOL del = False;
-
-  if (!share_name_fnum(fnum,fname)) return;
-
-  fd2 = open(fname,O_RDONLY,0);
-  if (fd2 < 0) return;
-  if (read(fd2,buf,16) != 16)
-    del = True;
-  close(fd2);
-
-  if (!del) {
-    t = IVAL(buf,0);
-    pid = IVAL(buf,8);
-  }
+/*******************************************************************
+ Remove an oplock port and mode entry from a share mode.
+********************************************************************/
 
-  if (!del)
-    if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
-      del = True;
-
-  if (!del && t == Files[fnum].open_time && pid==(int)getpid())
-    del = True;
-
-  if (del) {
-    if (!unlink(fname)) 
-      DEBUG(2,("Deleted share file %s\n",fname));
-    else {
-      DEBUG(3,("Pending delete share file %s\n",fname));
-      if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
-      strcpy(share_del_pending,fname);
-    }
-  }
-#endif
+BOOL remove_share_oplock(int token, files_struct *fsp)
+{
+       return share_ops->mod_entry(token, fsp, remove_share_oplock_fn, NULL);
 }
-  
 
 /*******************************************************************
-set the share mode of a file
+ Static function that actually does the work for the generic function
+ below.
 ********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+
+static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
+                                   void *param)
 {
-#if FAST_SHARE_MODES
-  int pid = (int)getpid();
-  struct stat st;
-  shm_offset_t new_off;
-  share_mode_record *new_p;
-  
-  
-  if (fstat(Files[fnum].fd,&st) != 0) return(False);
-  
-  if (!shm_lock()) return (False);
-  new_off = shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
-  if (new_off == NULL_OFFSET) return (False);
-  new_p = (share_mode_record *)shm_offset2addr(new_off);
-  new_p->locking_version = LOCKING_VERSION;
-  new_p->share_mode = mode;
-  new_p->time = Files[fnum].open_time;
-  new_p->pid = pid;
-  new_p->st_dev = st.st_dev;
-  new_p->st_ino = st.st_ino;
-  strcpy(new_p->file_name,Files[fnum].name);
-  new_p->next_offset = shm_get_userdef_off();
-  shm_set_userdef_off(new_off);
-
-
-  DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
-
-  if (!shm_unlock()) return (False);
-  return(True);
+  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;
+}
 
-#else
-  pstring fname;
-  int fd2;
-  char buf[16];
-  int pid = (int)getpid();
+/*******************************************************************
+ Downgrade a oplock type from exclusive to level II.
+********************************************************************/
 
-  if (!share_name_fnum(fnum,fname)) return(False);
+BOOL downgrade_share_oplock(int token, files_struct *fsp)
+{
+    return share_ops->mod_entry(token, fsp, downgrade_share_oplock_fn, NULL);
+}
 
-  {
-    int old_umask = umask(0);
-    fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
-    umask(old_umask);
-  }
-  if (fd2 < 0) {
-    DEBUG(2,("Failed to create share file %s\n",fname));
-    return(False);
-  }
+/*******************************************************************
+ Static function that actually does the work for the generic function
+ below.
+********************************************************************/
 
-  SIVAL(buf,0,Files[fnum].open_time);
-  SIVAL(buf,4,mode);
-  SIVAL(buf,8,pid);
-  SIVAL(buf,12,LOCKING_VERSION);
+struct mod_val {
+       int new_share_mode;
+       uint16 new_oplock;
+};
 
-  if (write(fd2,buf,16) != 16) {
-    close(fd2);
-    unlink(fname);
-    return(False);
-  }
+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;
+}
 
-  write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+/*******************************************************************
+ Modify a share mode on a file. Used by the delete open file code.
+ Return False on fail, True on success.
+********************************************************************/
 
-  close(fd2);
+BOOL modify_share_mode(int token, files_struct *fsp, int new_mode, uint16 new_oplock)
+{
+       struct mod_val mv;
 
-  DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+       mv.new_share_mode = new_mode;
+    mv.new_oplock = new_oplock;
 
-  return(True);
-#endif
+       return share_ops->mod_entry(token, fsp, modify_share_mode_fn, (void *)&mv);
 }
-  
 
 /*******************************************************************
-cleanup any stale share files
+ Call the specified function on each entry under management by the
+ share mode system.
 ********************************************************************/
-void clean_share_modes(void)
+
+int share_mode_forall(void (*fn)(share_mode_entry *, char *))
 {
-#ifdef USE_SHMEM
-  share_mode_record *scanner_p;
-  share_mode_record *prev_p;
-  int pid;
-  
-  if (!shm_lock()) return;
-  
-  scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
-  prev_p = scanner_p;
-  while(scanner_p)
-  {
-     pid = scanner_p->pid;
-     
-     if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
-     {
-       DEBUG(2,("Deleting stale share mode record"));
-       if(prev_p == scanner_p)
-       {
-          shm_set_userdef_off(scanner_p->next_offset);
-          shm_free(shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off());
-           prev_p = scanner_p;
-       }
-       else
-       {
-          prev_p->next_offset = scanner_p->next_offset;
-          shm_free(shm_addr2offset(scanner_p));
-           scanner_p = (share_mode_record *)shm_offset2addr(prev_p->next_offset);
-       }
-       
-     }
-     else
-     {
-       prev_p = scanner_p ;
-       scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset);
-     }
-  }
-    
+       if (!share_ops) return 0;
+       return share_ops->forall(fn);
+}
 
-  shm_unlock();
-  return;
-  
-#else
-  char *lockdir = lp_lockdir();
-  void *dir;
-  char *s;
-
-  if (!*lockdir) return;
-
-  dir = opendir(lockdir);
-  if (!dir) return;
-
-  while ((s=readdirname(dir))) {
-    char buf[16];
-    int pid;
-    int fd;
-    pstring lname;
-    int dev,inode;
-
-    if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
-
-    strcpy(lname,lp_lockdir());
-    trim_string(lname,NULL,"/");
-    strcat(lname,"/");
-    strcat(lname,s);
-
-    fd = open(lname,O_RDONLY,0);
-    if (fd < 0) continue;
-
-    if (read(fd,buf,16) != 16) {
-      close(fd);
-      if (!unlink(lname))
-       printf("Deleted corrupt share file %s\n",s);
-      continue;
-    }
-    close(fd);
-
-    pid = IVAL(buf,8);
-
-    if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
-      if (!unlink(lname))
-       printf("Deleted stale share file %s\n",s);
-    }
-  }
+/*******************************************************************
+ Dump the state of the system.
+********************************************************************/
 
-  closedir(dir);
-#endif
+void share_status(FILE *f)
+{
+       share_ops->status(f);
 }