summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/include/vfs.h1
-rw-r--r--source3/lib/util.c108
-rw-r--r--source3/locking/posix.c124
-rw-r--r--source3/smbd/vfs-wrap.c5
-rw-r--r--source3/smbd/vfs.c9
6 files changed, 141 insertions, 108 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d418ac4268..11a8df31a4 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -335,7 +335,6 @@ char *readdirname(DIR *p);
BOOL is_in_path(char *name, name_compare_entry *namelist);
void set_namearray(name_compare_entry **ppname_array, char *namelist);
void free_namearray(name_compare_entry *name_array);
-uint32 map_lock_offset(uint32 high, uint32 low);
BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
BOOL is_myname(char *s);
void set_remote_arch(enum remote_arch_types type);
@@ -3374,6 +3373,7 @@ int vfswrap_unlink(char *path);
int vfswrap_chmod(char *path, mode_t mode);
int vfswrap_utime(char *path, struct utimbuf *times);
int vfswrap_ftruncate(int fd, SMB_OFF_T offset);
+BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
/*The following definitions come from smbd/vfs.c */
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index a09991a0e7..1b4e57f2ac 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -137,6 +137,7 @@ struct vfs_ops {
int (*chmod)(char *path, mode_t mode);
int (*utime)(char *path, struct utimbuf *times);
int (*ftruncate)(int fd, SMB_OFF_T offset);
+ BOOL (*lock)(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
};
struct vfs_options {
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 8ac9223f2e..36373e9847 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1499,57 +1499,15 @@ void free_namearray(name_compare_entry *name_array)
}
/****************************************************************************
- Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
-****************************************************************************/
-
-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);
-}
-
-/****************************************************************************
-routine to do file locking
+ Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
+ is dealt with in posix.c
****************************************************************************/
BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
-#if HAVE_FCNTL_LOCK
SMB_STRUCT_FLOCK lock;
int ret;
-#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,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
lock.l_type = type;
@@ -1561,22 +1519,9 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
errno = 0;
ret = fcntl(fd,op,&lock);
- if (errno == EFBIG)
- {
- if( DEBUGLVL( 0 ))
- {
- dbgtext("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;
- lock.l_len = count & 0x7fffffff;
- ret = fcntl(fd,op,&lock);
- }
if (errno != 0)
- DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+ DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
/* a lock query */
if (op == SMB_F_GETLK)
@@ -1586,7 +1531,7 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
(lock.l_pid != 0) &&
(lock.l_pid != sys_getpid()))
{
- DEBUG(3,("fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
+ DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
return(True);
}
@@ -1597,56 +1542,15 @@ BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
/* a lock set or unset */
if (ret == -1)
{
- DEBUG(3,("lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
+ DEBUG(3,("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);
-
- lock.l_len = (orig_count & 0x7FFFFFFF);
- lock.l_start = (SMB_OFF_T)map_lock_offset(off_high, off_low);
- ret = fcntl(fd,op,&lock);
- if (ret == -1)
- {
- if (errno == EINVAL)
- {
- DEBUG(3,("locking not supported? returning True\n"));
- return(True);
- }
- return False;
- }
- DEBUG(3,("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);
}
/* everything went OK */
- DEBUG(8,("Lock call successful\n"));
+ DEBUG(8,("fcntl_lock: Lock call successful\n"));
return(True);
-#else
- return(False);
-#endif
}
/*******************************************************************
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;
}
diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c
index a3dd752023..5db1689450 100644
--- a/source3/smbd/vfs-wrap.c
+++ b/source3/smbd/vfs-wrap.c
@@ -305,3 +305,8 @@ int vfswrap_ftruncate(int fd, SMB_OFF_T offset)
result = sys_ftruncate(fd, offset);
return result;
}
+
+BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
+{
+ return fcntl_lock(fd, op, offset, count,type);
+}
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index d76d64684b..895d84d51c 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -65,7 +65,8 @@ struct vfs_ops default_vfs_ops = {
vfswrap_unlink,
vfswrap_chmod,
vfswrap_utime,
- vfswrap_ftruncate
+ vfswrap_ftruncate,
+ vfswrap_lock
};
/****************************************************************************
@@ -210,7 +211,11 @@ BOOL vfs_init_custom(connection_struct *conn)
}
if (conn->vfs_ops.ftruncate == NULL) {
- conn->vfs_ops.ftruncate= default_vfs_ops.ftruncate;
+ conn->vfs_ops.ftruncate = default_vfs_ops.ftruncate;
+ }
+
+ if (conn->vfs_ops.lock == NULL) {
+ conn->vfs_ops.lock = default_vfs_ops.lock;
}
return True;