2006-02-22 23:14:58 +03:00
/*
* linux / fs / jfs / ioctl . c
*
* Copyright ( C ) 2006 Herbert Poetzl
* adapted from Remy Card ' s ext2 / ioctl . c
*/
# include <linux/fs.h>
# include <linux/ctype.h>
# include <linux/capability.h>
2008-02-16 01:37:46 +03:00
# include <linux/mount.h>
2006-02-22 23:14:58 +03:00
# include <linux/time.h>
2006-10-18 21:55:46 +04:00
# include <linux/sched.h>
2006-02-22 23:14:58 +03:00
# include <asm/current.h>
# include <asm/uaccess.h>
# include "jfs_incore.h"
# include "jfs_dinode.h"
# include "jfs_inode.h"
static struct {
long jfs_flag ;
long ext2_flag ;
} jfs_map [ ] = {
2006-08-29 22:06:16 +04:00
{ JFS_NOATIME_FL , FS_NOATIME_FL } ,
{ JFS_DIRSYNC_FL , FS_DIRSYNC_FL } ,
{ JFS_SYNC_FL , FS_SYNC_FL } ,
{ JFS_SECRM_FL , FS_SECRM_FL } ,
{ JFS_UNRM_FL , FS_UNRM_FL } ,
{ JFS_APPEND_FL , FS_APPEND_FL } ,
{ JFS_IMMUTABLE_FL , FS_IMMUTABLE_FL } ,
2006-02-22 23:14:58 +03:00
{ 0 , 0 } ,
} ;
static long jfs_map_ext2 ( unsigned long flags , int from )
{
int index = 0 ;
long mapped = 0 ;
while ( jfs_map [ index ] . jfs_flag ) {
if ( from ) {
if ( jfs_map [ index ] . ext2_flag & flags )
mapped | = jfs_map [ index ] . jfs_flag ;
} else {
if ( jfs_map [ index ] . jfs_flag & flags )
mapped | = jfs_map [ index ] . ext2_flag ;
}
index + + ;
}
return mapped ;
}
2008-01-28 01:58:51 +03:00
long jfs_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2006-02-22 23:14:58 +03:00
{
2008-01-28 01:58:51 +03:00
struct inode * inode = filp - > f_dentry - > d_inode ;
2006-02-22 23:14:58 +03:00
struct jfs_inode_info * jfs_inode = JFS_IP ( inode ) ;
unsigned int flags ;
switch ( cmd ) {
case JFS_IOC_GETFLAGS :
2007-04-25 18:36:20 +04:00
jfs_get_inode_flags ( jfs_inode ) ;
2006-02-22 23:14:58 +03:00
flags = jfs_inode - > mode2 & JFS_FL_USER_VISIBLE ;
flags = jfs_map_ext2 ( flags , 0 ) ;
return put_user ( flags , ( int __user * ) arg ) ;
case JFS_IOC_SETFLAGS : {
unsigned int oldflags ;
2008-02-16 01:37:46 +03:00
int err ;
2006-02-22 23:14:58 +03:00
2008-02-16 01:37:46 +03:00
err = mnt_want_write ( filp - > f_path . mnt ) ;
if ( err )
return err ;
2006-02-22 23:14:58 +03:00
2008-02-16 01:37:46 +03:00
if ( ! is_owner_or_cap ( inode ) ) {
err = - EACCES ;
goto setflags_out ;
}
if ( get_user ( flags , ( int __user * ) arg ) ) {
err = - EFAULT ;
goto setflags_out ;
}
2006-02-22 23:14:58 +03:00
flags = jfs_map_ext2 ( flags , 1 ) ;
if ( ! S_ISDIR ( inode - > i_mode ) )
flags & = ~ JFS_DIRSYNC_FL ;
2007-11-15 03:58:56 +03:00
/* Is it quota file? Do not allow user to mess with it */
2008-02-16 01:37:46 +03:00
if ( IS_NOQUOTA ( inode ) ) {
err = - EPERM ;
goto setflags_out ;
}
2008-01-28 01:58:51 +03:00
/* Lock against other parallel changes of flags */
mutex_lock ( & inode - > i_mutex ) ;
2007-04-25 18:36:20 +04:00
jfs_get_inode_flags ( jfs_inode ) ;
2006-02-22 23:14:58 +03:00
oldflags = jfs_inode - > mode2 ;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the relevant capability .
*/
if ( ( oldflags & JFS_IMMUTABLE_FL ) | |
( ( flags ^ oldflags ) &
( JFS_APPEND_FL | JFS_IMMUTABLE_FL ) ) ) {
2008-01-28 01:58:51 +03:00
if ( ! capable ( CAP_LINUX_IMMUTABLE ) ) {
mutex_unlock ( & inode - > i_mutex ) ;
2008-02-16 01:37:46 +03:00
err = - EPERM ;
goto setflags_out ;
2008-01-28 01:58:51 +03:00
}
2006-02-22 23:14:58 +03:00
}
flags = flags & JFS_FL_USER_MODIFIABLE ;
flags | = oldflags & ~ JFS_FL_USER_MODIFIABLE ;
jfs_inode - > mode2 = flags ;
jfs_set_inode_flags ( inode ) ;
2008-01-28 01:58:51 +03:00
mutex_unlock ( & inode - > i_mutex ) ;
2006-02-22 23:14:58 +03:00
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
2008-02-16 01:37:46 +03:00
setflags_out :
mnt_drop_write ( filp - > f_path . mnt ) ;
return err ;
2006-02-22 23:14:58 +03:00
}
default :
return - ENOTTY ;
}
}
2008-01-28 02:02:02 +03:00
# ifdef CONFIG_COMPAT
long jfs_compat_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
{
/* While these ioctl numbers defined with 'long' and have different
* numbers than the 64 bit ABI ,
* the actual implementation only deals with ints and is compatible .
*/
switch ( cmd ) {
case JFS_IOC_GETFLAGS32 :
cmd = JFS_IOC_GETFLAGS ;
break ;
case JFS_IOC_SETFLAGS32 :
cmd = JFS_IOC_SETFLAGS ;
break ;
}
return jfs_ioctl ( filp , cmd , arg ) ;
}
# endif