2005-04-16 15:20:36 -07: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 12:17:46 -08:00
# include <linux/capability.h>
2005-04-16 15:20:36 -07:00
# include <linux/fs.h>
2008-02-15 14:37:46 -08:00
# include <linux/mount.h>
2005-04-16 15:20:36 -07:00
# include <linux/sched.h>
# include <linux/xattr.h>
# include <asm/uaccess.h>
# include "hfsplus_fs.h"
2010-10-01 05:41:31 +02:00
static int hfsplus_ioctl_getflags ( struct file * file , int __user * user_flags )
2005-04-16 15:20:36 -07:00
{
2010-10-01 05:41:31 +02:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2010-10-01 05:43:31 +02:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2010-10-01 05:41:31 +02:00
unsigned int flags = 0 ;
2010-10-14 09:54:33 -04:00
if ( inode - > i_flags & S_IMMUTABLE )
2010-10-01 05:41:31 +02:00
flags | = FS_IMMUTABLE_FL ;
2010-12-16 14:44:51 +02:00
if ( inode - > i_flags & S_APPEND )
2010-10-01 05:41:31 +02:00
flags | = FS_APPEND_FL ;
2010-10-01 05:43:31 +02:00
if ( hip - > userflags & HFSPLUS_FLG_NODUMP )
2010-10-01 05:41:31 +02:00
flags | = FS_NODUMP_FL ;
return put_user ( flags , user_flags ) ;
}
static int hfsplus_ioctl_setflags ( struct file * file , int __user * user_flags )
{
struct inode * inode = file - > f_path . dentry - > d_inode ;
2010-10-01 05:43:31 +02:00
struct hfsplus_inode_info * hip = HFSPLUS_I ( inode ) ;
2005-04-16 15:20:36 -07:00
unsigned int flags ;
2010-10-01 05:41:31 +02:00
int err = 0 ;
2005-04-16 15:20:36 -07:00
2010-10-01 05:41:31 +02:00
err = mnt_want_write ( file - > f_path . mnt ) ;
if ( err )
2010-10-01 05:41:35 +02:00
goto out ;
2005-04-16 15:20:36 -07:00
2011-03-23 16:43:26 -07:00
if ( ! inode_owner_or_capable ( inode ) ) {
2010-10-01 05:41:31 +02:00
err = - EACCES ;
goto out_drop_write ;
}
2005-04-16 15:20:36 -07:00
2010-10-01 05:41:31 +02:00
if ( get_user ( flags , user_flags ) ) {
err = - EFAULT ;
goto out_drop_write ;
}
2010-10-01 05:41:35 +02:00
mutex_lock ( & inode - > i_mutex ) ;
2010-10-14 09:54:33 -04:00
if ( ( flags & ( FS_IMMUTABLE_FL | FS_APPEND_FL ) ) | |
inode - > i_flags & ( S_IMMUTABLE | S_APPEND ) ) {
2010-10-01 05:41:31 +02:00
if ( ! capable ( CAP_LINUX_IMMUTABLE ) ) {
err = - EPERM ;
2010-10-01 05:41:35 +02:00
goto out_unlock_inode ;
2005-04-16 15:20:36 -07:00
}
}
2010-10-01 05:41:31 +02:00
/* don't silently ignore unsupported ext2 flags */
if ( flags & ~ ( FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL ) ) {
err = - EOPNOTSUPP ;
2010-10-01 05:41:35 +02:00
goto out_unlock_inode ;
2010-10-01 05:41:31 +02:00
}
2010-10-14 09:54:33 -04:00
if ( flags & FS_IMMUTABLE_FL )
2010-10-01 05:41:31 +02:00
inode - > i_flags | = S_IMMUTABLE ;
2010-10-14 09:54:33 -04:00
else
2010-10-01 05:41:31 +02:00
inode - > i_flags & = ~ S_IMMUTABLE ;
2010-10-14 09:54:33 -04:00
if ( flags & FS_APPEND_FL )
2010-10-01 05:41:31 +02:00
inode - > i_flags | = S_APPEND ;
2010-10-14 09:54:33 -04:00
else
2010-10-01 05:41:31 +02:00
inode - > i_flags & = ~ S_APPEND ;
2010-10-14 09:54:33 -04:00
2010-10-01 05:41:31 +02:00
if ( flags & FS_NODUMP_FL )
2010-10-01 05:43:31 +02:00
hip - > userflags | = HFSPLUS_FLG_NODUMP ;
2010-10-01 05:41:31 +02:00
else
2010-10-01 05:43:31 +02:00
hip - > userflags & = ~ HFSPLUS_FLG_NODUMP ;
2010-10-01 05:41:31 +02:00
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
2010-10-01 05:41:35 +02:00
out_unlock_inode :
2010-10-25 20:39:07 +02:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-10-01 05:41:31 +02:00
out_drop_write :
mnt_drop_write ( file - > f_path . mnt ) ;
2010-10-01 05:41:35 +02:00
out :
2010-10-01 05:41:31 +02: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 ) ;
2005-04-16 15:20:36 -07:00
default :
return - ENOTTY ;
}
}
int hfsplus_setxattr ( struct dentry * dentry , const char * name ,
const void * value , size_t size , int flags )
{
struct inode * inode = dentry - > d_inode ;
struct hfs_find_data fd ;
hfsplus_cat_entry entry ;
struct hfsplus_cat_file * file ;
int res ;
if ( ! S_ISREG ( inode - > i_mode ) | | HFSPLUS_IS_RSRC ( inode ) )
return - EOPNOTSUPP ;
2010-10-01 05:42:59 +02:00
res = hfs_find_init ( HFSPLUS_SB ( inode - > i_sb ) - > cat_tree , & fd ) ;
2005-04-16 15:20:36 -07:00
if ( res )
return res ;
res = hfsplus_find_cat ( inode - > i_sb , inode - > i_ino , & fd ) ;
if ( res )
goto out ;
hfs_bnode_read ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
file = & entry . file ;
if ( ! strcmp ( name , " hfs.type " ) ) {
if ( size = = 4 )
memcpy ( & file - > user_info . fdType , value , 4 ) ;
else
res = - ERANGE ;
} else if ( ! strcmp ( name , " hfs.creator " ) ) {
if ( size = = 4 )
memcpy ( & file - > user_info . fdCreator , value , 4 ) ;
else
res = - ERANGE ;
} else
res = - EOPNOTSUPP ;
2010-11-23 14:38:15 +01:00
if ( ! res ) {
2005-04-16 15:20:36 -07:00
hfs_bnode_write ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
2010-11-23 14:38:15 +01:00
hfsplus_mark_inode_dirty ( inode , HFSPLUS_I_CAT_DIRTY ) ;
}
2005-04-16 15:20:36 -07:00
out :
hfs_find_exit ( & fd ) ;
return res ;
}
ssize_t hfsplus_getxattr ( struct dentry * dentry , const char * name ,
void * value , size_t size )
{
struct inode * inode = dentry - > d_inode ;
struct hfs_find_data fd ;
hfsplus_cat_entry entry ;
struct hfsplus_cat_file * file ;
ssize_t res = 0 ;
if ( ! S_ISREG ( inode - > i_mode ) | | HFSPLUS_IS_RSRC ( inode ) )
return - EOPNOTSUPP ;
if ( size ) {
2010-10-01 05:42:59 +02:00
res = hfs_find_init ( HFSPLUS_SB ( inode - > i_sb ) - > cat_tree , & fd ) ;
2005-04-16 15:20:36 -07:00
if ( res )
return res ;
res = hfsplus_find_cat ( inode - > i_sb , inode - > i_ino , & fd ) ;
if ( res )
goto out ;
hfs_bnode_read ( fd . bnode , & entry , fd . entryoffset ,
sizeof ( struct hfsplus_cat_file ) ) ;
}
file = & entry . file ;
if ( ! strcmp ( name , " hfs.type " ) ) {
if ( size > = 4 ) {
memcpy ( value , & file - > user_info . fdType , 4 ) ;
res = 4 ;
} else
res = size ? - ERANGE : 4 ;
} else if ( ! strcmp ( name , " hfs.creator " ) ) {
if ( size > = 4 ) {
memcpy ( value , & file - > user_info . fdCreator , 4 ) ;
res = 4 ;
} else
res = size ? - ERANGE : 4 ;
} else
2010-10-15 05:45:00 -07:00
res = - EOPNOTSUPP ;
2005-04-16 15:20:36 -07:00
out :
if ( size )
hfs_find_exit ( & fd ) ;
return res ;
}
# define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
ssize_t hfsplus_listxattr ( struct dentry * dentry , char * buffer , size_t size )
{
struct inode * inode = dentry - > d_inode ;
if ( ! S_ISREG ( inode - > i_mode ) | | HFSPLUS_IS_RSRC ( inode ) )
return - EOPNOTSUPP ;
if ( ! buffer | | ! size )
return HFSPLUS_ATTRLIST_SIZE ;
if ( size < HFSPLUS_ATTRLIST_SIZE )
return - ERANGE ;
strcpy ( buffer , " hfs.type " ) ;
strcpy ( buffer + sizeof ( " hfs.type " ) , " hfs.creator " ) ;
return HFSPLUS_ATTRLIST_SIZE ;
}