2005-04-16 15:20:36 -07:00
/*
* linux / fs / ext2 / ioctl . c
*
* Copyright ( C ) 1993 , 1994 , 1995
* Remy Card ( card @ masi . ibp . fr )
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie ( Paris VI )
*/
# include "ext2.h"
2006-01-11 12:17:46 -08:00
# include <linux/capability.h>
2005-04-16 15:20:36 -07:00
# include <linux/time.h>
# include <linux/sched.h>
2006-08-29 19:06:20 +01:00
# include <linux/compat.h>
# include <linux/smp_lock.h>
2005-04-16 15:20:36 -07:00
# include <asm/current.h>
# include <asm/uaccess.h>
int ext2_ioctl ( struct inode * inode , struct file * filp , unsigned int cmd ,
unsigned long arg )
{
struct ext2_inode_info * ei = EXT2_I ( inode ) ;
unsigned int flags ;
ext2_debug ( " cmd = %u, arg = %lu \n " , cmd , arg ) ;
switch ( cmd ) {
case EXT2_IOC_GETFLAGS :
2007-05-08 00:31:04 -07:00
ext2_get_inode_flags ( ei ) ;
2005-04-16 15:20:36 -07:00
flags = ei - > i_flags & EXT2_FL_USER_VISIBLE ;
return put_user ( flags , ( int __user * ) arg ) ;
case EXT2_IOC_SETFLAGS : {
unsigned int oldflags ;
if ( IS_RDONLY ( inode ) )
return - EROFS ;
2007-07-17 15:00:08 +05:30
if ( ! is_owner_or_cap ( inode ) )
2005-04-16 15:20:36 -07:00
return - EACCES ;
if ( get_user ( flags , ( int __user * ) arg ) )
return - EFAULT ;
if ( ! S_ISDIR ( inode - > i_mode ) )
flags & = ~ EXT2_DIRSYNC_FL ;
2006-12-06 20:37:33 -08:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-16 15:20:36 -07:00
oldflags = ei - > i_flags ;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the relevant capability .
*
* This test looks nicer . Thanks to Pauline Middelink
*/
if ( ( flags ^ oldflags ) & ( EXT2_APPEND_FL | EXT2_IMMUTABLE_FL ) ) {
2006-12-06 20:37:33 -08:00
if ( ! capable ( CAP_LINUX_IMMUTABLE ) ) {
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-16 15:20:36 -07:00
return - EPERM ;
2006-12-06 20:37:33 -08:00
}
2005-04-16 15:20:36 -07:00
}
flags = flags & EXT2_FL_USER_MODIFIABLE ;
flags | = oldflags & ~ EXT2_FL_USER_MODIFIABLE ;
ei - > i_flags = flags ;
2006-12-06 20:37:33 -08:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-16 15:20:36 -07:00
ext2_set_inode_flags ( inode ) ;
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
return 0 ;
}
case EXT2_IOC_GETVERSION :
return put_user ( inode - > i_generation , ( int __user * ) arg ) ;
case EXT2_IOC_SETVERSION :
2007-07-17 15:00:08 +05:30
if ( ! is_owner_or_cap ( inode ) )
2005-04-16 15:20:36 -07:00
return - EPERM ;
if ( IS_RDONLY ( inode ) )
return - EROFS ;
if ( get_user ( inode - > i_generation , ( int __user * ) arg ) )
return - EFAULT ;
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
return 0 ;
default :
return - ENOTTY ;
}
}
2006-08-29 19:06:20 +01:00
# ifdef CONFIG_COMPAT
long ext2_compat_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
2006-12-08 02:36:37 -08:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2006-08-29 19:06:20 +01:00
int ret ;
/* These are just misnamed, they actually get/put from/to user an int */
switch ( cmd ) {
case EXT2_IOC32_GETFLAGS :
cmd = EXT2_IOC_GETFLAGS ;
break ;
case EXT2_IOC32_SETFLAGS :
cmd = EXT2_IOC_SETFLAGS ;
break ;
case EXT2_IOC32_GETVERSION :
cmd = EXT2_IOC_GETVERSION ;
break ;
case EXT2_IOC32_SETVERSION :
cmd = EXT2_IOC_SETVERSION ;
break ;
default :
return - ENOIOCTLCMD ;
}
lock_kernel ( ) ;
ret = ext2_ioctl ( inode , file , cmd , ( unsigned long ) compat_ptr ( arg ) ) ;
unlock_kernel ( ) ;
return ret ;
}
# endif