2005-04-17 02:20:36 +04:00
/*
* linux / fs / hfsplus / ioctl . c
*
* Copyright ( C ) 2003
* Ethan Benson < erbenson @ alaska . net >
* partially derived from 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 )
*
* hfsplus ioctls
*/
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/fs.h>
2008-02-16 01:37:46 +03:00
# include <linux/mount.h>
2005-04-17 02:20:36 +04:00
# include <linux/sched.h>
# include <asm/uaccess.h>
# include "hfsplus_fs.h"
2012-02-07 00:14:40 +04:00
/*
* " Blessing " an HFS + filesystem writes metadata to the superblock informing
* the platform firmware which file to boot from
*/
static int hfsplus_ioctl_bless ( struct file * file , int __user * user_flags )
{
struct dentry * dentry = file - > f_path . dentry ;
struct inode * inode = dentry - > d_inode ;
struct hfsplus_sb_info * sbi = HFSPLUS_SB ( inode - > i_sb ) ;
struct hfsplus_vh * vh = sbi - > s_vhdr ;
struct hfsplus_vh * bvh = sbi - > s_backup_vhdr ;
2012-06-18 01:05:25 +04:00
u32 cnid = ( unsigned long ) dentry - > d_fsdata ;
2012-02-07 00:14:40 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
mutex_lock ( & sbi - > vh_mutex ) ;
/* Directory containing the bootable system */
vh - > finder_info [ 0 ] = bvh - > finder_info [ 0 ] =
cpu_to_be32 ( parent_ino ( dentry ) ) ;
2012-06-18 01:05:25 +04:00
/*
* Bootloader . Just using the inode here breaks in the case of
* hard links - the firmware wants the ID of the hard link file ,
* but the inode points at the indirect inode
*/
vh - > finder_info [ 1 ] = bvh - > finder_info [ 1 ] = cpu_to_be32 ( cnid ) ;
2012-02-07 00:14:40 +04:00
/* Per spec, the OS X system folder - same as finder_info[0] here */
vh - > finder_info [ 5 ] = bvh - > finder_info [ 5 ] =
cpu_to_be32 ( parent_ino ( dentry ) ) ;
mutex_unlock ( & sbi - > vh_mutex ) ;
return 0 ;
}
2010-10-01 07:41:31 +04:00
static int hfsplus_ioctl_getflags ( struct file * file , int __user * user_flags )
2005-04-17 02:20:36 +04:00
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) ;
2010-10-01 07:43:31 +04:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2010-10-01 07:41:31 +04:00
unsigned int flags = 0 ;
2010-10-14 17:54:33 +04:00
if ( inode - > i_flags & S_IMMUTABLE )
2010-10-01 07:41:31 +04:00
flags | = FS_IMMUTABLE_FL ;
2010-12-16 15:44:51 +03:00
if ( inode - > i_flags & S_APPEND )
2010-10-01 07:41:31 +04:00
flags | = FS_APPEND_FL ;
2010-10-01 07:43:31 +04:00
if ( hip - > userflags & HFSPLUS_FLG_NODUMP )
2010-10-01 07:41:31 +04:00
flags | = FS_NODUMP_FL ;
return put_user ( flags , user_flags ) ;
}
static int hfsplus_ioctl_setflags ( struct file * file , int __user * user_flags )
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) ;
2010-10-01 07:43:31 +04:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2005-04-17 02:20:36 +04:00
unsigned int flags ;
2010-10-01 07:41:31 +04:00
int err = 0 ;
2005-04-17 02:20:36 +04:00
2011-11-23 20:57:51 +04:00
err = mnt_want_write_file ( file ) ;
2010-10-01 07:41:31 +04:00
if ( err )
2010-10-01 07:41:35 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
2011-03-24 02:43:26 +03:00
if ( ! inode_owner_or_capable ( inode ) ) {
2010-10-01 07:41:31 +04:00
err = - EACCES ;
goto out_drop_write ;
}
2005-04-17 02:20:36 +04:00
2010-10-01 07:41:31 +04:00
if ( get_user ( flags , user_flags ) ) {
err = - EFAULT ;
goto out_drop_write ;
}
2010-10-01 07:41:35 +04:00
mutex_lock ( & inode - > i_mutex ) ;
2010-10-14 17:54:33 +04:00
if ( ( flags & ( FS_IMMUTABLE_FL | FS_APPEND_FL ) ) | |
inode - > i_flags & ( S_IMMUTABLE | S_APPEND ) ) {
2010-10-01 07:41:31 +04:00
if ( ! capable ( CAP_LINUX_IMMUTABLE ) ) {
err = - EPERM ;
2010-10-01 07:41:35 +04:00
goto out_unlock_inode ;
2005-04-17 02:20:36 +04:00
}
}
2010-10-01 07:41:31 +04:00
/* don't silently ignore unsupported ext2 flags */
if ( flags & ~ ( FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL ) ) {
err = - EOPNOTSUPP ;
2010-10-01 07:41:35 +04:00
goto out_unlock_inode ;
2010-10-01 07:41:31 +04:00
}
2010-10-14 17:54:33 +04:00
if ( flags & FS_IMMUTABLE_FL )
2010-10-01 07:41:31 +04:00
inode - > i_flags | = S_IMMUTABLE ;
2010-10-14 17:54:33 +04:00
else
2010-10-01 07:41:31 +04:00
inode - > i_flags & = ~ S_IMMUTABLE ;
2010-10-14 17:54:33 +04:00
if ( flags & FS_APPEND_FL )
2010-10-01 07:41:31 +04:00
inode - > i_flags | = S_APPEND ;
2010-10-14 17:54:33 +04:00
else
2010-10-01 07:41:31 +04:00
inode - > i_flags & = ~ S_APPEND ;
2010-10-14 17:54:33 +04:00
2010-10-01 07:41:31 +04:00
if ( flags & FS_NODUMP_FL )
2010-10-01 07:43:31 +04:00
hip - > userflags | = HFSPLUS_FLG_NODUMP ;
2010-10-01 07:41:31 +04:00
else
2010-10-01 07:43:31 +04:00
hip - > userflags & = ~ HFSPLUS_FLG_NODUMP ;
2010-10-01 07:41:31 +04:00
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
2010-10-01 07:41:35 +04:00
out_unlock_inode :
2010-10-25 22:39:07 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-10-01 07:41:31 +04:00
out_drop_write :
2011-12-09 17:06:57 +04:00
mnt_drop_write_file ( file ) ;
2010-10-01 07:41:35 +04:00
out :
2010-10-01 07:41:31 +04:00
return err ;
}
long hfsplus_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
void __user * argp = ( void __user * ) arg ;
switch ( cmd ) {
case HFSPLUS_IOC_EXT2_GETFLAGS :
return hfsplus_ioctl_getflags ( file , argp ) ;
case HFSPLUS_IOC_EXT2_SETFLAGS :
return hfsplus_ioctl_setflags ( file , argp ) ;
2012-02-07 00:14:40 +04:00
case HFSPLUS_IOC_BLESS :
return hfsplus_ioctl_bless ( file , argp ) ;
2005-04-17 02:20:36 +04:00
default :
return - ENOTTY ;
}
}