summaryrefslogtreecommitdiff
path: root/source3/locking
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-05-02 03:20:47 +0000
committerJeremy Allison <jra@samba.org>2000-05-02 03:20:47 +0000
commitba020b0612ee975df15ceaf2eabf0cc3f208dc3e (patch)
treecaba9b545ebd4f9edf62da2da012481c119a957c /source3/locking
parent693ffb8466ada58ecc59fde754ba79fc6f51528d (diff)
downloadsamba-ba020b0612ee975df15ceaf2eabf0cc3f208dc3e.tar.gz
samba-ba020b0612ee975df15ceaf2eabf0cc3f208dc3e.tar.bz2
samba-ba020b0612ee975df15ceaf2eabf0cc3f208dc3e.zip
Moved uglyness needed in fcntl locking (64->32 bit mapping, NFS
errors etc.) into locking/posix.c, where it is needed. fcntl_lock in lib/util.c is now very small and clean. Added (*lock) op to vfs layer. Jeremy. (This used to be commit 46092ee1410faa4e3c143d80a960a8adaa19d7fc)
Diffstat (limited to 'source3/locking')
-rw-r--r--source3/locking/posix.c124
1 files changed, 121 insertions, 3 deletions
diff --git a/source3/locking/posix.c b/source3/locking/posix.c
index 7cada20ac3..094cb87bc8 100644
--- a/source3/locking/posix.c
+++ b/source3/locking/posix.c
@@ -612,6 +612,124 @@ static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
}
/****************************************************************************
+ Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
+****************************************************************************/
+
+static uint32 map_lock_offset(uint32 high, uint32 low)
+{
+ unsigned int i;
+ uint32 mask = 0;
+ uint32 highcopy = high;
+
+ /*
+ * Try and find out how many significant bits there are in high.
+ */
+
+ for(i = 0; highcopy; i++)
+ highcopy >>= 1;
+
+ /*
+ * We use 31 bits not 32 here as POSIX
+ * lock offsets may not be negative.
+ */
+
+ mask = (~0) << (31 - i);
+
+ if(low & mask)
+ return 0; /* Fail. */
+
+ high <<= (31 - i);
+
+ return (high|low);
+}
+
+/****************************************************************************
+ Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
+ broken NFS implementations.
+****************************************************************************/
+
+static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ int ret;
+ struct connection_struct *conn = fsp->conn;
+
+#if defined(LARGE_SMB_OFF_T)
+ /*
+ * In the 64 bit locking case we store the original
+ * values in case we have to map to a 32 bit lock on
+ * a filesystem that doesn't support 64 bit locks.
+ */
+ SMB_OFF_T orig_offset = offset;
+ SMB_OFF_T orig_count = count;
+#endif /* LARGE_SMB_OFF_T */
+
+ DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fd,op,(double)offset,(double)count,type));
+
+ ret = conn->vfs_ops.lock(fsp->fd,op,offset,count,type);
+
+ if (!ret && (errno == EFBIG)) {
+ if( DEBUGLVL( 0 )) {
+ dbgtext("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n", (double)offset,(double)count);
+ dbgtext("a 'file too large' error. This can happen when using 64 bit lock offsets\n");
+ dbgtext("on 32 bit NFS mounted file systems. Retrying with 32 bit truncated length.\n");
+ }
+ /* 32 bit NFS file system, retry with smaller offset */
+ errno = 0;
+ count &= 0x7fffffff;
+ ret = conn->vfs_ops.lock(fsp->fd,op,offset,count,type);
+ }
+
+ /* A lock query - just return. */
+ if (op == SMB_F_GETLK)
+ return ret;
+
+ /* A lock set or unset. */
+ if (!ret) {
+ DEBUG(3,("posix_fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ (double)offset,(double)count,op,type,strerror(errno)));
+
+ /* Perhaps it doesn't support this sort of locking ? */
+ if (errno == EINVAL) {
+#if defined(LARGE_SMB_OFF_T)
+ {
+ /*
+ * Ok - if we get here then we have a 64 bit lock request
+ * that has returned EINVAL. Try and map to 31 bits for offset
+ * and length and try again. This may happen if a filesystem
+ * doesn't support 64 bit offsets (efs/ufs) although the underlying
+ * OS does.
+ */
+ uint32 off_low = (orig_offset & 0xFFFFFFFF);
+ uint32 off_high = ((orig_offset >> 32) & 0xFFFFFFFF);
+
+ count = (orig_count & 0x7FFFFFFF);
+ offset = (SMB_OFF_T)map_lock_offset(off_high, off_low);
+ ret = conn->vfs_ops.lock(fsp->fd,op,offset,count,type);
+ if (!ret) {
+ if (errno == EINVAL) {
+ DEBUG(3,("posix_fcntl_lock: locking not supported? returning True\n"));
+ return(True);
+ }
+ return False;
+ }
+ DEBUG(3,("posix_fcntl_lock: 64 -> 32 bit modified lock call successful\n"));
+ return True;
+ }
+#else /* LARGE_SMB_OFF_T */
+ DEBUG(3,("locking not supported? returning True\n"));
+ return(True);
+#endif /* LARGE_SMB_OFF_T */
+ }
+
+ return(False);
+ }
+
+ DEBUG(8,("posix_fcntl_lock: Lock call successful\n"));
+
+ return(True);
+}
+
+/****************************************************************************
POSIX function to see if a file region is locked. Returns True if the
region is locked, False otherwise.
****************************************************************************/
@@ -639,7 +757,7 @@ BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_co
* fd. So we don't need to use map_lock_type here.
*/
- return fcntl_lock(fsp->fd,SMB_F_GETLK,offset,count,posix_lock_type);
+ return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
}
/****************************************************************************
@@ -673,7 +791,7 @@ BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_cou
* below. JRA.
*/
- ret = fcntl_lock(fsp->fd,SMB_F_SETLK,offset,count,posix_lock_type);
+ ret = posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type);
if (ret)
add_posix_lock_entry(fsp,offset,count,posix_lock_type);
@@ -992,7 +1110,7 @@ BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u
DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n",
(double)offset, (double)count ));
- if (!fcntl_lock(fsp->fd,SMB_F_SETLK,offset,count,F_UNLCK))
+ if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK))
ret = False;
}