Fix incorrect conversion of fd_attempt_open() calls to vfs_ops.open().
[samba.git] / source3 / smbd / open.c
index ad4dd9f52f18deb3c08024e0be4e99b974e53a7e..2c12d425b95778d74fafee456f231076fed33017 100644 (file)
 extern int DEBUGLEVEL;
 
 extern pstring sesssetup_user;
-extern int global_oplocks_open;
-extern uint16 oplock_port;
+extern uint16 global_oplock_port;
 
 
 /****************************************************************************
 fd support routines - attempt to do a dos_open
 ****************************************************************************/
-static int fd_attempt_open(char *fname, int flags, mode_t mode)
+static int fd_attempt_open(struct connection_struct *conn, char *fname, 
+                          int flags, mode_t mode)
 {
-  int fd = dos_open(fname,flags,mode);
+  int fd = conn->vfs_ops.open(fname,flags,mode);
 
   /* Fix for files ending in '.' */
   if((fd == -1) && (errno == ENOENT) &&
      (strchr(fname,'.')==NULL))
     {
       pstrcat(fname,".");
-      fd = dos_open(fname,flags,mode);
+      fd = conn->vfs_ops.open(fname,flags,mode);
     }
 
 #if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
@@ -71,7 +71,7 @@ static int fd_attempt_open(char *fname, int flags, mode_t mode)
           char tmp = p[max_len];
 
           p[max_len] = '\0';
-          if ((fd = dos_open(fname,flags,mode)) == -1)
+          if ((fd = conn->vfs_ops.open(fname,flags,mode)) == -1)
             p[max_len] = tmp;
         }
     }
@@ -145,10 +145,17 @@ static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr)
 fd support routines - attempt to close the file referenced by this fd.
 Decrements the ref_count and returns it.
 ****************************************************************************/
-uint16 fd_attempt_close(file_fd_struct *fd_ptr)
+uint16 fd_attempt_close(files_struct *fsp)
 {
   extern struct current_user current_user;
-  uint16 ret_ref = fd_ptr->ref_count;
+  file_fd_struct *fd_ptr = fsp->fd_ptr;
+  uint16 ret_ref;
+
+  if (fd_ptr != NULL) {
+      ret_ref = fd_ptr->ref_count;
+  } else {
+      return 0;
+  }
 
   DEBUG(3,("fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d.\n",
           fd_ptr->fd, (unsigned int)fd_ptr->dev, (double)fd_ptr->inode,
@@ -162,11 +169,11 @@ uint16 fd_attempt_close(file_fd_struct *fd_ptr)
 
   if(fd_ptr->ref_count == 0) {
     if(fd_ptr->fd != -1)
-      close(fd_ptr->fd);
+      fsp->conn->vfs_ops.close(fd_ptr->fd);
     if(fd_ptr->fd_readonly != -1)
-      close(fd_ptr->fd_readonly);
+      fsp->conn->vfs_ops.close(fd_ptr->fd_readonly);
     if(fd_ptr->fd_writeonly != -1)
-      close(fd_ptr->fd_writeonly);
+      fsp->conn->vfs_ops.close(fd_ptr->fd_writeonly);
     /*
      * Delete this fd_ptr.
      */
@@ -185,7 +192,9 @@ This is really ugly code, as due to POSIX locking braindamage we must
 fork and then attempt to open the file, and return success or failure
 via an exit code.
 ****************************************************************************/
-static BOOL check_access_allowed_for_current_user( char *fname, int accmode )
+static BOOL check_access_allowed_for_current_user(struct connection_struct
+                                                 *conn, char *fname, 
+                                                 int accmode )
 {
   pid_t child_pid;
 
@@ -236,7 +245,7 @@ static BOOL check_access_allowed_for_current_user( char *fname, int accmode )
      */
     int fd;
     DEBUG(9,("check_access_allowed_for_current_user: Child - attempting to open %s with mode %d.\n", fname, accmode ));
-    if((fd = fd_attempt_open( fname, accmode, 0)) < 0) {
+    if((fd = fd_attempt_open(conn, fname, accmode, 0)) < 0) {
       /* Access denied. */
       _exit(EACCES);
     }
@@ -274,7 +283,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
   pstring fname;
   SMB_STRUCT_STAT statbuf;
   file_fd_struct *fd_ptr;
-  int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
+  int accmode = (flags & O_ACCMODE);
 
   fsp->open = False;
   fsp->fd_ptr = 0;
@@ -313,7 +322,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
   /* this handles a bug in Win95 - it doesn't say to create the file when it 
      should */
   if (conn->printer) {
-         flags |= O_CREAT;
+         flags |= (O_CREAT|O_EXCL);
   }
 
 /*
@@ -326,7 +335,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
    * open fd table.
    */
   if(sbuf == 0) {
-    if(dos_stat(fname, &statbuf) < 0) {
+    if(conn->vfs_ops.stat(dos_to_unix(fname,False), &statbuf) < 0) {
       if(errno != ENOENT) {
         DEBUG(3,("Error doing stat on file %s (%s)\n",
                  fname,strerror(errno)));
@@ -367,7 +376,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
      */
 
     if(!fd_is_in_uid_cache(fd_ptr, (uid_t)current_user.uid)) {
-      if(!check_access_allowed_for_current_user( fname, accmode )) {
+      if(!check_access_allowed_for_current_user(conn, fname, accmode )) {
         /* Error - permission denied. */
         DEBUG(3,("Permission denied opening file %s (flags=%d, accmode = %d)\n",
               fname, flags, accmode));
@@ -424,7 +433,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
     fd_ptr->real_open_flags = O_RDWR;
     /* Set the flags as needed without the read/write modes. */
     open_flags = flags & ~(O_RDWR|O_WRONLY|O_RDONLY);
-    fd_ptr->fd = fd_attempt_open(fname, open_flags|O_RDWR, mode);
+    fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|O_RDWR, mode);
     /*
      * On some systems opening a file for R/W access on a read only
      * filesystems sets errno to EROFS.
@@ -435,7 +444,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
     if((fd_ptr->fd == -1) && (errno == EACCES)) {
 #endif /* EROFS */
       if(accmode != O_RDWR) {
-        fd_ptr->fd = fd_attempt_open(fname, open_flags|accmode, mode);
+        fd_ptr->fd = fd_attempt_open(conn, fname, open_flags|accmode, mode);
         fd_ptr->real_open_flags = accmode;
       }
     }
@@ -444,15 +453,15 @@ static void open_file(files_struct *fsp,connection_struct *conn,
   if ((fd_ptr->fd >=0) && 
       conn->printer && lp_minprintspace(SNUM(conn))) {
     pstring dname;
-    int dum1,dum2,dum3;
+    SMB_BIG_UINT dum1,dum2,dum3;
     char *p;
     pstrcpy(dname,fname);
     p = strrchr(dname,'/');
     if (p) *p = 0;
-    if (sys_disk_free(dname,&dum1,&dum2,&dum3) < 
-       lp_minprintspace(SNUM(conn))) {
-      if(fd_attempt_close(fd_ptr) == 0)
-        dos_unlink(fname);
+    if (conn->vfs_ops.disk_free(dname,&dum1,&dum2,&dum3) < 
+       (SMB_BIG_UINT)lp_minprintspace(SNUM(conn))) {
+      if(fd_attempt_close(fsp) == 0)
+        conn->vfs_ops.unlink(fname);
       fsp->fd_ptr = 0;
       errno = ENOSPC;
       return;
@@ -464,7 +473,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
     DEBUG(3,("Error opening file %s (%s) (flags=%d)\n",
       fname,strerror(errno),flags));
     /* Ensure the ref_count is decremented. */
-    fd_attempt_close(fd_ptr);
+    fd_attempt_close(fsp);
     check_for_pipe(fname);
     return;
   }
@@ -473,12 +482,12 @@ static void open_file(files_struct *fsp,connection_struct *conn,
   {
     if(sbuf == 0) {
       /* Do the fstat */
-      if(sys_fstat(fd_ptr->fd, &statbuf) == -1) {
+      if(conn->vfs_ops.fstat(fd_ptr->fd, &statbuf) == -1) {
         /* Error - backout !! */
         DEBUG(3,("Error doing fstat on fd %d, file %s (%s)\n",
                  fd_ptr->fd, fname,strerror(errno)));
         /* Ensure the ref_count is decremented. */
-        fd_attempt_close(fd_ptr);
+        fd_attempt_close(fsp);
         return;
       }
       sbuf = &statbuf;
@@ -507,7 +516,6 @@ static void open_file(files_struct *fsp,connection_struct *conn,
     fsp->granted_oplock = False;
     fsp->sent_oplock_break = False;
     fsp->is_directory = False;
-    fsp->delete_on_close = False;
     fsp->conn = conn;
     /*
      * Note that the file name here is the *untranslated* name
@@ -528,7 +536,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
      */
     if (fsp->print_file && lp_postscript(SNUM(conn)) && fsp->can_write) {
            DEBUG(3,("Writing postscript line\n"));
-           write_file(fsp,"%!\n",3);
+           conn->vfs_ops.write(fsp->fd_ptr->fd,"%!\n",3);
     }
       
     DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
@@ -537,24 +545,37 @@ static void open_file(files_struct *fsp,connection_struct *conn,
             conn->num_files_open));
 
   }
+}
+
+/****************************************************************************
+ If it's a read-only file, and we were compiled with mmap enabled,
+ try and mmap the file. This is split out from open_file() above
+ as mmap'ing the file can cause the kernel reference count to
+ be incremented, which can cause kernel oplocks to be refused.
+ Splitting this call off allows the kernel oplock to be granted, then
+ the file mmap'ed.
+****************************************************************************/
 
+static void mmap_open_file(files_struct *fsp)
+{
 #if WITH_MMAP
   /* mmap it if read-only */
   if (!fsp->can_write) {
-         fsp->mmap_size = file_size(fname);
-         fsp->mmap_ptr = (char *)mmap(NULL,fsp->mmap_size,
-                                      PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,0);
-
-         if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) {
-                 DEBUG(3,("Failed to mmap() %s - %s\n",
-                          fname,strerror(errno)));
-                 fsp->mmap_ptr = NULL;
+         fsp->mmap_size = dos_file_size(fsp->fsp_name);
+         if (fsp->mmap_size < MAX_MMAP_SIZE) {
+                 fsp->mmap_ptr = (char *)sys_mmap(NULL,fsp->mmap_size,
+                                              PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,(SMB_OFF_T)0);
+
+                 if (fsp->mmap_ptr == (char *)-1 || !fsp->mmap_ptr) {
+                         DEBUG(3,("Failed to mmap() %s - %s\n",
+                                  fsp->fsp_name,strerror(errno)));
+                         fsp->mmap_ptr = NULL;
+                 }
          }
   }
 #endif
 }
 
-
 /****************************************************************************
   C. Hoch 11/22/95
   Helper for open_file_shared. 
@@ -563,27 +584,26 @@ static void open_file(files_struct *fsp,connection_struct *conn,
 static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token, 
                                   BOOL *share_locked)
 {
-  if (fsp->can_write){
-#ifdef LARGE_SMB_OFF_T
-    if (is_locked(fsp,conn,0x3FFFFFFFFFFFFFFFLL,0,F_WRLCK)){
-#else
-    if (is_locked(fsp,conn,0x3FFFFFFF,0,F_WRLCK)){
-#endif
-      /* If share modes are in force for this connection we
-         have the share entry locked. Unlock it before closing. */
-      if (*share_locked && lp_share_modes(SNUM(conn)))
-        unlock_share_entry( conn, fsp->fd_ptr->dev, 
-                            fsp->fd_ptr->inode, token);
-      close_file(fsp,False);   
-      /* Share mode no longer locked. */
-      *share_locked = False;
-      errno = EACCES;
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRlock;
-    }
-    else
-      sys_ftruncate(fsp->fd_ptr->fd,0); 
-  }
+       if (fsp->can_write){
+               SMB_OFF_T mask2 = ((SMB_OFF_T)0x3) << (SMB_OFF_T_BITS-4);
+               SMB_OFF_T mask = (mask2<<2);
+               
+               if (is_locked(fsp,conn,~mask,0,F_WRLCK)){
+                       /* If share modes are in force for this connection we
+                          have the share entry locked. Unlock it before closing. */
+                       if (*share_locked && lp_share_modes(SNUM(conn)))
+                               unlock_share_entry( conn, fsp->fd_ptr->dev, 
+                                                   fsp->fd_ptr->inode, token);
+                       close_file(fsp,False);   
+                       /* Share mode no longer locked. */
+                       *share_locked = False;
+                       errno = EACCES;
+                       unix_ERR_class = ERRDOS;
+                 unix_ERR_code = ERRlock;
+               } else {
+                       sys_ftruncate(fsp->fd_ptr->fd,0); 
+               }
+       }
 }
 
 
@@ -648,13 +668,31 @@ static 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;
-  int old_deny_mode = (share->share_mode >>4)&7;
+  int old_open_mode = GET_OPEN_MODE(share->share_mode);
+  int old_deny_mode = GET_DENY_MODE(share->share_mode);
+
+  /*
+   * Don't allow any open once the delete on close flag has been
+   * set.
+   */
+
+  if(GET_DELETE_ON_CLOSE_FLAG(share->share_mode))
+  {
+    DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n",
+          fname ));
+    unix_ERR_class = ERRDOS;
+    unix_ERR_code = ERRnoaccess;
+    return False;
+  }
 
   if (old_deny_mode > 4 || old_open_mode > 2)
   {
     DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n",
                deny_mode,old_deny_mode,old_open_mode,fname));
+
+    unix_ERR_class = ERRDOS;
+    unix_ERR_code = ERRbadshare;
+
     return False;
   }
 
@@ -670,6 +708,10 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
       DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
                 deny_mode,old_deny_mode,old_open_mode,
                 share->pid,fname, fcbopen, *flags, access_allowed));
+
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadshare;
+
       return False;
     }
 
@@ -680,6 +722,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
       *flags = O_WRONLY;
 
   }
+
   return True;
 }
 
@@ -687,14 +730,17 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
 /****************************************************************************
 open a file with a share mode
 ****************************************************************************/
-void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int share_mode,int ofun,
-                     mode_t mode,int oplock_request, int *Access,int *action)
+void open_file_shared(files_struct *fsp, connection_struct *conn,
+                          char *fname, int share_mode, int ofun, 
+                          mode_t mode, int oplock_request, int *Access,
+                          int *action)
 {
   int flags=0;
   int flags2=0;
-  int deny_mode = (share_mode>>4)&7;
+  int deny_mode = GET_DENY_MODE(share_mode);
+  BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
   SMB_STRUCT_STAT sbuf;
-  BOOL file_existed = file_exist(fname,&sbuf);
+  BOOL file_existed = vfs_file_exist(conn, dos_to_unix(fname,False), &sbuf);
   BOOL share_locked = False;
   BOOL fcbopen = False;
   int token;
@@ -705,6 +751,9 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
   fsp->open = False;
   fsp->fd_ptr = 0;
 
+  DEBUG(10,("open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n",
+        fname, share_mode, ofun, (int)mode,  oplock_request ));
+
   /* this is for OS/2 EAs - try and say we don't support them */
   if (strstr(fname,".+,;=[].")) 
   {
@@ -716,33 +765,40 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
     unix_ERR_code = ERROR_EAS_NOT_SUPPORTED;
 #endif /* OS2_WPS_FIX */
 
+    DEBUG(5,("open_file_shared: OS/2 EA's are not supported.\n"));
     return;
   }
 
-  if ((ofun & 0x3) == 0 && file_existed)  
+  if ((GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) && file_existed)  
   {
+    DEBUG(5,("open_file_shared: create new requested for file %s and file already exists.\n",
+          fname ));
     errno = EEXIST;
     return;
   }
       
-  if (ofun & 0x10)
+  if (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST)
     flags2 |= O_CREAT;
-  if ((ofun & 0x3) == 2)
+
+  if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)
     flags2 |= O_TRUNC;
 
+  if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL)
+    flags2 |= O_EXCL;
+
   /* note that we ignore the append flag as 
      append does not mean the same thing under dos and unix */
 
-  switch (share_mode&0xF)
+  switch (GET_OPEN_MODE(share_mode))
   {
-    case 1
+    case DOS_OPEN_WRONLY
       flags = O_WRONLY; 
       break;
-    case 0xF
+    case DOS_OPEN_FCB
       fcbopen = True;
       flags = O_RDWR; 
       break;
-    case 2
+    case DOS_OPEN_RDWR
       flags = O_RDWR; 
       break;
     default:
@@ -751,7 +807,7 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
   }
 
 #if defined(O_SYNC)
-  if (share_mode&(1<<14)) {
+  if (GET_FILE_SYNC_OPENMODE(share_mode)) {
          flags2 |= O_SYNC;
   }
 #endif /* O_SYNC */
@@ -761,6 +817,8 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
   {
     if (!fcbopen) 
     {
+      DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n",
+            fname, !CAN_WRITE(conn) ? "share" : "file" ));
       errno = EACCES;
       return;
     }
@@ -774,7 +832,8 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
     return;
   }
 
-  if (deny_mode == DENY_FCB) deny_mode = DENY_DOS;
+  if (deny_mode == DENY_FCB)
+    deny_mode = DENY_DOS;
 
   if (lp_share_modes(SNUM(conn))) 
   {
@@ -845,8 +904,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
             free((char *)old_shares);
             unlock_share_entry(conn, dev, inode, token);
             errno = EACCES;
-            unix_ERR_class = ERRDOS;
-            unix_ERR_code = ERRbadshare;
             return;
           }
 
@@ -890,17 +947,19 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
     switch (flags) 
     {
       case O_RDONLY:
-        open_mode = 0;
+        open_mode = DOS_OPEN_RDONLY;
         break;
       case O_RDWR:
-        open_mode = 2;
+        open_mode = DOS_OPEN_RDWR;
         break;
       case O_WRONLY:
-        open_mode = 1;
+        open_mode = DOS_OPEN_WRONLY;
         break;
     }
 
-    fsp->share_mode = (deny_mode<<4) | open_mode;
+    fsp->share_mode = SET_DENY_MODE(deny_mode) | 
+                      SET_OPEN_MODE(open_mode) | 
+                      SET_ALLOW_SHARE_DELETE(allow_share_delete);
 
     if (Access)
       (*Access) = open_mode;
@@ -918,46 +977,47 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
     if (lp_share_modes(SNUM(conn)))
     {
       uint16 port = 0;
+
       /* JRA. Currently this only services Exlcusive and batch
          oplocks (no other opens on this file). This needs to
          be extended to level II oplocks (multiple reader
          oplocks). */
 
-      if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) && 
-             !IS_VETO_OPLOCK_PATH(conn,fname))
+      if((oplock_request) && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) && 
+             !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp) )
       {
-        fsp->granted_oplock = True;
-        fsp->sent_oplock_break = False;
-        global_oplocks_open++;
-        port = oplock_port;
-
-        DEBUG(5,("open_file_shared: granted oplock (%x) on file %s, \
-dev = %x, inode = %.0f\n", oplock_request, fname, (unsigned int)dev, (double)inode));
-
+        port = global_oplock_port;
       }
       else
       {
         port = 0;
         oplock_request = 0;
       }
+
       set_share_mode(token, fsp, port, oplock_request);
     }
 
     if ((flags2&O_TRUNC) && file_existed)
       truncate_unless_locked(fsp,conn,token,&share_locked);
+
+    /*
+     * Attempt to mmap a read only file.
+     * Moved until after a kernel oplock may
+     * be granted due to reference count issues. JRA.
+     */
+    mmap_open_file(fsp);
   }
 
   if (share_locked && lp_share_modes(SNUM(conn)))
     unlock_share_entry( conn, dev, inode, token);
 }
 
-
-
 /****************************************************************************
  Open a directory from an NT SMB call.
 ****************************************************************************/
+
 int open_directory(files_struct *fsp,connection_struct *conn,
-                  char *fname, int smb_ofun, int unixmode, int *action)
+                  char *fname, int smb_ofun, mode_t unixmode, int *action)
 {
        extern struct current_user current_user;
        SMB_STRUCT_STAT st;
@@ -967,7 +1027,8 @@ int open_directory(files_struct *fsp,connection_struct *conn,
                 * Create the directory.
                 */
 
-               if(dos_mkdir(fname, unixmode) < 0) {
+               if(conn->vfs_ops.mkdir(dos_to_unix(fname,False), 
+                                      unix_mode(conn,aDIR)) < 0) {
                        DEBUG(0,("open_directory: unable to create %s. Error was %s\n",
                                 fname, strerror(errno) ));
                        return -1;
@@ -979,7 +1040,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
                 * Check that it *was* a directory.
                 */
 
-               if(dos_stat(fname, &st) < 0) {
+               if(conn->vfs_ops.stat(dos_to_unix(fname,False), &st) < 0) {
                        DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n",
                                 fname, strerror(errno) ));
                        return -1;
@@ -1037,6 +1098,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
 check if the share mode on a file allows it to be deleted or unlinked
 return True if sharing doesn't prevent the operation
 ********************************************************************/
+
 BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
 {
   int i;
@@ -1052,7 +1114,7 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
   if(!lp_share_modes(SNUM(conn)))
     return True;
 
-  if (dos_stat(fname,&sbuf) == -1) return(True);
+  if (conn->vfs_ops.stat(dos_to_unix(fname,False),&sbuf) == -1) return(True);
 
   dev = sbuf.st_dev;
   inode = sbuf.st_ino;
@@ -1136,9 +1198,20 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
           }
         }
 
-        /* someone else has a share lock on it, check to see 
-           if we can too */
-        if ((share_entry->share_mode != DENY_DOS) || (share_entry->pid != pid))
+        /* 
+         * If this is a delete request and ALLOW_SHARE_DELETE is set then allow 
+         * this to proceed. This takes precedence over share modes.
+         */
+
+        if(!rename_op && GET_ALLOW_SHARE_DELETE(share_entry->share_mode))
+          continue;
+
+        /* 
+         * Someone else has a share lock on it, check to see 
+         * if we can too.
+         */
+
+        if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) || (share_entry->pid != pid))
           goto free_and_exit;
 
       } /* end for */
@@ -1153,8 +1226,14 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
 
   /* XXXX exactly what share mode combinations should be allowed for
      deleting/renaming? */
-  /* If we got here then either there were no share modes or
-     all share modes were DENY_DOS and the pid == getpid() */
+  /* 
+   * If we got here then either there were no share modes or
+   * all share modes were DENY_DOS and the pid == getpid() or
+   * delete access was requested and all share modes had the
+   * ALLOW_SHARE_DELETE bit set (takes precedence over other
+   * share modes).
+   */
+
   ret = True;
 
 free_and_exit:
@@ -1164,5 +1243,3 @@ free_and_exit:
     free((char *)old_shares);
   return(ret);
 }
-
-