1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

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 46092ee141)
This commit is contained in:
Jeremy Allison 2000-05-02 03:20:47 +00:00
parent 693ffb8466
commit ba020b0612
6 changed files with 141 additions and 108 deletions

View File

@ -335,7 +335,6 @@ char *readdirname(DIR *p);
BOOL is_in_path(char *name, name_compare_entry *namelist); BOOL is_in_path(char *name, name_compare_entry *namelist);
void set_namearray(name_compare_entry **ppname_array, char *namelist); void set_namearray(name_compare_entry **ppname_array, char *namelist);
void free_namearray(name_compare_entry *name_array); 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 fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
BOOL is_myname(char *s); BOOL is_myname(char *s);
void set_remote_arch(enum remote_arch_types type); 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_chmod(char *path, mode_t mode);
int vfswrap_utime(char *path, struct utimbuf *times); int vfswrap_utime(char *path, struct utimbuf *times);
int vfswrap_ftruncate(int fd, SMB_OFF_T offset); 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 */ /*The following definitions come from smbd/vfs.c */

View File

@ -137,6 +137,7 @@ struct vfs_ops {
int (*chmod)(char *path, mode_t mode); int (*chmod)(char *path, mode_t mode);
int (*utime)(char *path, struct utimbuf *times); int (*utime)(char *path, struct utimbuf *times);
int (*ftruncate)(int fd, SMB_OFF_T offset); 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 { struct vfs_options {

View File

@ -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 :-). Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
****************************************************************************/ is dealt with in posix.c
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
****************************************************************************/ ****************************************************************************/
BOOL fcntl_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type) 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; SMB_STRUCT_FLOCK lock;
int ret; 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)); DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
lock.l_type = 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; errno = 0;
ret = fcntl(fd,op,&lock); 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) 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 */ /* a lock query */
if (op == SMB_F_GETLK) 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 != 0) &&
(lock.l_pid != sys_getpid())) (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); 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 */ /* a lock set or unset */
if (ret == -1) 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))); (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); return(False);
} }
/* everything went OK */ /* everything went OK */
DEBUG(8,("Lock call successful\n")); DEBUG(8,("fcntl_lock: Lock call successful\n"));
return(True); return(True);
#else
return(False);
#endif
} }
/******************************************************************* /*******************************************************************

View File

@ -611,6 +611,124 @@ static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
return True; return True;
} }
/****************************************************************************
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 POSIX function to see if a file region is locked. Returns True if the
region is locked, False otherwise. 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. * 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. * 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) if (ret)
add_posix_lock_entry(fsp,offset,count,posix_lock_type); 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", DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n",
(double)offset, (double)count )); (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; ret = False;
} }

View File

@ -305,3 +305,8 @@ int vfswrap_ftruncate(int fd, SMB_OFF_T offset)
result = sys_ftruncate(fd, offset); result = sys_ftruncate(fd, offset);
return result; 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);
}

View File

@ -65,7 +65,8 @@ struct vfs_ops default_vfs_ops = {
vfswrap_unlink, vfswrap_unlink,
vfswrap_chmod, vfswrap_chmod,
vfswrap_utime, 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) { 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; return True;