2005-04-17 02:20:36 +04:00
/*
* fs / cifs / ioctl . c
*
* vfs operations that deal with io control
*
2013-10-15 00:31:32 +04:00
* Copyright ( C ) International Business Machines Corp . , 2005 , 2013
2005-04-17 02:20:36 +04:00
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See
* the GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2005-04-29 09:41:04 +04:00
2005-04-17 02:20:36 +04:00
# include <linux/fs.h>
2013-11-14 10:05:36 +04:00
# include <linux/file.h>
# include <linux/mount.h>
# include <linux/mm.h>
# include <linux/pagemap.h>
2005-04-17 02:20:36 +04:00
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_debug.h"
2005-04-29 09:41:04 +04:00
# include "cifsfs.h"
2015-07-05 02:40:10 +03:00
# include "cifs_ioctl.h"
2015-06-28 07:18:36 +03:00
# include <linux/btrfs.h>
2005-04-17 02:20:36 +04:00
2017-04-04 10:12:04 +03:00
static long cifs_ioctl_copychunk ( unsigned int xid , struct file * dst_file ,
2015-12-03 14:59:50 +03:00
unsigned long srcfd )
{
int rc ;
struct fd src_file ;
struct inode * src_inode ;
2017-04-04 10:12:04 +03:00
cifs_dbg ( FYI , " ioctl copychunk range \n " ) ;
2015-12-03 14:59:50 +03:00
/* the destination must be opened for writing */
if ( ! ( dst_file - > f_mode & FMODE_WRITE ) ) {
cifs_dbg ( FYI , " file target not open for write \n " ) ;
return - EINVAL ;
}
/* check if target volume is readonly and take reference */
rc = mnt_want_write_file ( dst_file ) ;
if ( rc ) {
cifs_dbg ( FYI , " mnt_want_write failed with rc %d \n " , rc ) ;
return rc ;
}
src_file = fdget ( srcfd ) ;
if ( ! src_file . file ) {
rc = - EBADF ;
goto out_drop_write ;
}
if ( src_file . file - > f_op - > unlocked_ioctl ! = cifs_ioctl ) {
rc = - EBADF ;
cifs_dbg ( VFS , " src file seems to be from a different filesystem type \n " ) ;
goto out_fput ;
}
src_inode = file_inode ( src_file . file ) ;
rc = - EINVAL ;
if ( S_ISDIR ( src_inode - > i_mode ) )
goto out_fput ;
2017-02-10 13:33:51 +03:00
rc = cifs_file_copychunk_range ( xid , src_file . file , 0 , dst_file , 0 ,
src_inode - > i_size , 0 ) ;
2017-04-26 19:10:17 +03:00
if ( rc > 0 )
rc = 0 ;
2013-11-14 10:05:36 +04:00
out_fput :
fdput ( src_file ) ;
out_drop_write :
mnt_drop_write_file ( dst_file ) ;
return rc ;
}
2015-07-05 02:40:10 +03:00
static long smb_mnt_get_fsinfo ( unsigned int xid , struct cifs_tcon * tcon ,
void __user * arg )
{
int rc = 0 ;
struct smb_mnt_fs_info * fsinf ;
fsinf = kzalloc ( sizeof ( struct smb_mnt_fs_info ) , GFP_KERNEL ) ;
if ( fsinf = = NULL )
return - ENOMEM ;
fsinf - > version = 1 ;
fsinf - > protocol_id = tcon - > ses - > server - > vals - > protocol_id ;
fsinf - > device_characteristics =
le32_to_cpu ( tcon - > fsDevInfo . DeviceCharacteristics ) ;
fsinf - > device_type = le32_to_cpu ( tcon - > fsDevInfo . DeviceType ) ;
fsinf - > fs_attributes = le32_to_cpu ( tcon - > fsAttrInfo . Attributes ) ;
fsinf - > max_path_component =
le32_to_cpu ( tcon - > fsAttrInfo . MaxPathNameComponentLength ) ;
# ifdef CONFIG_CIFS_SMB2
fsinf - > vol_serial_number = tcon - > vol_serial_number ;
fsinf - > vol_create_time = le64_to_cpu ( tcon - > vol_create_time ) ;
fsinf - > share_flags = tcon - > share_flags ;
fsinf - > share_caps = le32_to_cpu ( tcon - > capabilities ) ;
fsinf - > sector_flags = tcon - > ss_flags ;
fsinf - > optimal_sector_size = tcon - > perf_sector_size ;
fsinf - > max_bytes_chunk = tcon - > max_bytes_chunk ;
fsinf - > maximal_access = tcon - > maximal_access ;
# endif /* SMB2 */
fsinf - > cifs_posix_caps = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
if ( copy_to_user ( arg , fsinf , sizeof ( struct smb_mnt_fs_info ) ) )
rc = - EFAULT ;
kfree ( fsinf ) ;
return rc ;
}
2008-05-15 09:51:55 +04:00
long cifs_ioctl ( struct file * filep , unsigned int command , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( filep ) ;
2005-04-17 02:20:36 +04:00
int rc = - ENOTTY ; /* strange error - but the precedent */
2012-06-20 11:21:16 +04:00
unsigned int xid ;
2005-04-29 09:41:07 +04:00
struct cifs_sb_info * cifs_sb ;
2010-09-21 03:01:31 +04:00
struct cifsFileInfo * pSMBFile = filep - > private_data ;
2011-05-27 08:34:02 +04:00
struct cifs_tcon * tcon ;
2005-04-29 09:41:04 +04:00
__u64 ExtAttrBits = 0 ;
2010-11-08 15:28:32 +03:00
__u64 caps ;
2005-04-29 09:41:04 +04:00
2012-06-20 11:21:16 +04:00
xid = get_xid ( ) ;
2005-04-29 09:41:04 +04:00
cifs_sb = CIFS_SB ( inode - > i_sb ) ;
2016-11-17 02:17:15 +03:00
cifs_dbg ( FYI , " cifs ioctl 0x%x \n " , command ) ;
2007-06-05 22:30:44 +04:00
switch ( command ) {
2006-08-29 22:06:16 +04:00
case FS_IOC_GETFLAGS :
2010-11-08 15:28:32 +03:00
if ( pSMBFile = = NULL )
break ;
tcon = tlink_tcon ( pSMBFile - > tlink ) ;
caps = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2013-10-15 00:31:32 +04:00
# ifdef CONFIG_CIFS_POSIX
2007-06-05 22:30:44 +04:00
if ( CIFS_UNIX_EXTATTR_CAP & caps ) {
2013-10-14 07:32:30 +04:00
__u64 ExtAttrMask = 0 ;
2012-09-19 03:20:26 +04:00
rc = CIFSGetExtAttr ( xid , tcon ,
pSMBFile - > fid . netfid ,
& ExtAttrBits , & ExtAttrMask ) ;
2007-06-05 22:30:44 +04:00
if ( rc = = 0 )
2005-04-29 09:41:04 +04:00
rc = put_user ( ExtAttrBits &
2006-08-29 22:06:16 +04:00
FS_FL_USER_VISIBLE ,
2005-04-29 09:41:04 +04:00
( int __user * ) arg ) ;
2013-10-15 00:31:32 +04:00
if ( rc ! = EOPNOTSUPP )
break ;
}
# endif /* CONFIG_CIFS_POSIX */
rc = 0 ;
if ( CIFS_I ( inode ) - > cifsAttrs & ATTR_COMPRESSED ) {
/* add in the compressed bit */
ExtAttrBits = FS_COMPR_FL ;
rc = put_user ( ExtAttrBits & FS_FL_USER_VISIBLE ,
( int __user * ) arg ) ;
2005-04-29 09:41:04 +04:00
}
break ;
2006-08-29 22:06:16 +04:00
case FS_IOC_SETFLAGS :
2010-11-08 15:28:32 +03:00
if ( pSMBFile = = NULL )
break ;
tcon = tlink_tcon ( pSMBFile - > tlink ) ;
caps = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2013-10-15 00:31:32 +04:00
if ( get_user ( ExtAttrBits , ( int __user * ) arg ) ) {
rc = - EFAULT ;
break ;
}
/*
* if ( CIFS_UNIX_EXTATTR_CAP & caps )
* rc = CIFSSetExtAttr ( xid , tcon ,
* pSMBFile - > fid . netfid ,
* extAttrBits ,
* & ExtAttrMask ) ;
* if ( rc ! = EOPNOTSUPP )
* break ;
*/
/* Currently only flag we can set is compressed flag */
if ( ( ExtAttrBits & FS_COMPR_FL ) = = 0 )
break ;
/* Try to set compress flag */
if ( tcon - > ses - > server - > ops - > set_compression ) {
rc = tcon - > ses - > server - > ops - > set_compression (
xid , tcon , pSMBFile ) ;
cifs_dbg ( FYI , " set compress flag rc %d \n " , rc ) ;
2005-04-29 09:41:04 +04:00
}
break ;
2013-11-25 07:53:17 +04:00
case CIFS_IOC_COPYCHUNK_FILE :
2017-04-04 10:12:04 +03:00
rc = cifs_ioctl_copychunk ( xid , filep , arg ) ;
2013-11-14 10:05:36 +04:00
break ;
2015-06-24 11:17:02 +03:00
case CIFS_IOC_SET_INTEGRITY :
if ( pSMBFile = = NULL )
break ;
tcon = tlink_tcon ( pSMBFile - > tlink ) ;
if ( tcon - > ses - > server - > ops - > set_integrity )
rc = tcon - > ses - > server - > ops - > set_integrity ( xid ,
tcon , pSMBFile ) ;
else
rc = - EOPNOTSUPP ;
break ;
2015-07-05 02:40:10 +03:00
case CIFS_IOC_GET_MNT_INFO :
tcon = tlink_tcon ( pSMBFile - > tlink ) ;
rc = smb_mnt_get_fsinfo ( xid , tcon , ( void __user * ) arg ) ;
break ;
2016-10-01 05:14:26 +03:00
case CIFS_ENUMERATE_SNAPSHOTS :
2017-05-03 18:39:08 +03:00
if ( pSMBFile = = NULL )
break ;
2016-10-01 05:14:26 +03:00
if ( arg = = 0 ) {
rc = - EINVAL ;
goto cifs_ioc_exit ;
}
tcon = tlink_tcon ( pSMBFile - > tlink ) ;
if ( tcon - > ses - > server - > ops - > enum_snapshots )
rc = tcon - > ses - > server - > ops - > enum_snapshots ( xid , tcon ,
pSMBFile , ( void __user * ) arg ) ;
else
rc = - EOPNOTSUPP ;
break ;
2005-04-17 02:20:36 +04:00
default :
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " unsupported ioctl \n " ) ;
2005-04-29 09:41:07 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2016-10-01 05:14:26 +03:00
cifs_ioc_exit :
2012-06-20 11:21:16 +04:00
free_xid ( xid ) ;
2005-04-17 02:20:36 +04:00
return rc ;
2007-06-05 22:30:44 +04:00
}