diff options
-rw-r--r-- | source3/include/proto.h | 2 | ||||
-rw-r--r-- | source3/include/vfs.h | 1 | ||||
-rw-r--r-- | source3/lib/util.c | 108 | ||||
-rw-r--r-- | source3/locking/posix.c | 124 | ||||
-rw-r--r-- | source3/smbd/vfs-wrap.c | 5 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 9 |
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; |