2019-05-30 02:57:50 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-07-14 20:08:37 +04:00
/*
* This file is part of UBIFS .
*
* Copyright ( C ) 2006 - 2008 Nokia Corporation .
* Copyright ( C ) 2006 , 2007 University of Szeged , Hungary
*
* Authors : Zoltan Sogor
* Artem Bityutskiy ( Б и т ю ц к и й А р т ё м )
* Adrian Hunter
*/
/* This file implements EXT2-compatible extended attribute ioctl() calls */
# include <linux/compat.h>
# include <linux/mount.h>
2021-04-07 15:36:44 +03:00
# include <linux/fileattr.h>
2008-07-14 20:08:37 +04:00
# include "ubifs.h"
2019-02-09 11:54:20 +03:00
/* Need to be kept consistent with checked flags in ioctl2ubifs() */
2019-12-10 01:23:25 +03:00
# define UBIFS_SETTABLE_IOCTL_FLAGS \
2019-02-09 11:54:20 +03:00
( FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \
FS_IMMUTABLE_FL | FS_DIRSYNC_FL )
2019-12-10 01:23:25 +03:00
/* Need to be kept consistent with checked flags in ubifs2ioctl() */
# define UBIFS_GETTABLE_IOCTL_FLAGS \
( UBIFS_SETTABLE_IOCTL_FLAGS | FS_ENCRYPT_FL )
2008-07-14 20:08:37 +04:00
/**
* ubifs_set_inode_flags - set VFS inode flags .
* @ inode : VFS inode to set flags for
*
* This function propagates flags from UBIFS inode object to VFS inode object .
*/
void ubifs_set_inode_flags ( struct inode * inode )
{
unsigned int flags = ubifs_inode ( inode ) - > flags ;
2017-10-09 22:15:35 +03:00
inode - > i_flags & = ~ ( S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC |
S_ENCRYPTED ) ;
2008-07-14 20:08:37 +04:00
if ( flags & UBIFS_SYNC_FL )
inode - > i_flags | = S_SYNC ;
if ( flags & UBIFS_APPEND_FL )
inode - > i_flags | = S_APPEND ;
if ( flags & UBIFS_IMMUTABLE_FL )
inode - > i_flags | = S_IMMUTABLE ;
if ( flags & UBIFS_DIRSYNC_FL )
inode - > i_flags | = S_DIRSYNC ;
2017-10-09 22:15:35 +03:00
if ( flags & UBIFS_CRYPT_FL )
inode - > i_flags | = S_ENCRYPTED ;
2008-07-14 20:08:37 +04:00
}
/*
* ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags .
* @ ioctl_flags : flags to convert
*
2017-04-14 09:16:06 +03:00
* This function converts ioctl flags ( @ FS_COMPR_FL , etc ) to UBIFS inode flags
2008-07-14 20:08:37 +04:00
* ( @ UBIFS_COMPR_FL , etc ) .
*/
static int ioctl2ubifs ( int ioctl_flags )
{
int ubifs_flags = 0 ;
if ( ioctl_flags & FS_COMPR_FL )
ubifs_flags | = UBIFS_COMPR_FL ;
if ( ioctl_flags & FS_SYNC_FL )
ubifs_flags | = UBIFS_SYNC_FL ;
if ( ioctl_flags & FS_APPEND_FL )
ubifs_flags | = UBIFS_APPEND_FL ;
if ( ioctl_flags & FS_IMMUTABLE_FL )
ubifs_flags | = UBIFS_IMMUTABLE_FL ;
if ( ioctl_flags & FS_DIRSYNC_FL )
ubifs_flags | = UBIFS_DIRSYNC_FL ;
return ubifs_flags ;
}
/*
* ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags .
* @ ubifs_flags : flags to convert
*
2017-04-14 09:16:06 +03:00
* This function converts UBIFS inode flags ( @ UBIFS_COMPR_FL , etc ) to ioctl
* flags ( @ FS_COMPR_FL , etc ) .
2008-07-14 20:08:37 +04:00
*/
static int ubifs2ioctl ( int ubifs_flags )
{
int ioctl_flags = 0 ;
if ( ubifs_flags & UBIFS_COMPR_FL )
ioctl_flags | = FS_COMPR_FL ;
if ( ubifs_flags & UBIFS_SYNC_FL )
ioctl_flags | = FS_SYNC_FL ;
if ( ubifs_flags & UBIFS_APPEND_FL )
ioctl_flags | = FS_APPEND_FL ;
if ( ubifs_flags & UBIFS_IMMUTABLE_FL )
ioctl_flags | = FS_IMMUTABLE_FL ;
if ( ubifs_flags & UBIFS_DIRSYNC_FL )
ioctl_flags | = FS_DIRSYNC_FL ;
2019-12-10 01:23:25 +03:00
if ( ubifs_flags & UBIFS_CRYPT_FL )
ioctl_flags | = FS_ENCRYPT_FL ;
2008-07-14 20:08:37 +04:00
return ioctl_flags ;
}
static int setflags ( struct inode * inode , int flags )
{
2021-04-07 15:36:44 +03:00
int err , release ;
2008-07-14 20:08:37 +04:00
struct ubifs_inode * ui = ubifs_inode ( inode ) ;
struct ubifs_info * c = inode - > i_sb - > s_fs_info ;
struct ubifs_budget_req req = { . dirtied_ino = 1 ,
2021-12-27 06:22:39 +03:00
. dirtied_ino_d = ALIGN ( ui - > data_len , 8 ) } ;
2008-07-14 20:08:37 +04:00
err = ubifs_budget_space ( c , & req ) ;
if ( err )
return err ;
mutex_lock ( & ui - > ui_mutex ) ;
2019-12-10 01:23:25 +03:00
ui - > flags & = ~ ioctl2ubifs ( UBIFS_SETTABLE_IOCTL_FLAGS ) ;
2019-12-10 01:23:24 +03:00
ui - > flags | = ioctl2ubifs ( flags ) ;
2008-07-14 20:08:37 +04:00
ubifs_set_inode_flags ( inode ) ;
2023-07-05 22:01:43 +03:00
inode_set_ctime_current ( inode ) ;
2008-07-14 20:08:37 +04:00
release = ui - > dirty ;
mark_inode_dirty_sync ( inode ) ;
mutex_unlock ( & ui - > ui_mutex ) ;
if ( release )
ubifs_release_budget ( c , & req ) ;
if ( IS_SYNC ( inode ) )
err = write_inode_now ( inode , 1 ) ;
return err ;
2021-04-07 15:36:44 +03:00
}
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
int ubifs_fileattr_get ( struct dentry * dentry , struct fileattr * fa )
{
struct inode * inode = d_inode ( dentry ) ;
int flags = ubifs2ioctl ( ubifs_inode ( inode ) - > flags ) ;
if ( d_is_special ( dentry ) )
return - ENOTTY ;
dbg_gen ( " get flags: %#x, i_flags %#x " , flags , inode - > i_flags ) ;
fileattr_fill_flags ( fa , flags ) ;
return 0 ;
2008-07-14 20:08:37 +04:00
}
2023-01-13 14:49:21 +03:00
int ubifs_fileattr_set ( struct mnt_idmap * idmap ,
2021-04-07 15:36:44 +03:00
struct dentry * dentry , struct fileattr * fa )
2008-07-14 20:08:37 +04:00
{
2021-04-07 15:36:44 +03:00
struct inode * inode = d_inode ( dentry ) ;
int flags = fa - > flags ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
if ( d_is_special ( dentry ) )
return - ENOTTY ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
if ( fileattr_has_fsx ( fa ) )
return - EOPNOTSUPP ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
if ( flags & ~ UBIFS_GETTABLE_IOCTL_FLAGS )
return - EOPNOTSUPP ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
flags & = UBIFS_SETTABLE_IOCTL_FLAGS ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
if ( ! S_ISDIR ( inode - > i_mode ) )
flags & = ~ FS_DIRSYNC_FL ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
dbg_gen ( " set flags: %#x, i_flags %#x " , flags , inode - > i_flags ) ;
return setflags ( inode , flags ) ;
}
2019-02-09 11:54:20 +03:00
2021-04-07 15:36:44 +03:00
long ubifs_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
int err ;
struct inode * inode = file_inode ( file ) ;
2008-07-14 20:08:37 +04:00
2021-04-07 15:36:44 +03:00
switch ( cmd ) {
2016-10-20 17:47:56 +03:00
case FS_IOC_SET_ENCRYPTION_POLICY : {
2016-10-20 00:24:47 +03:00
struct ubifs_info * c = inode - > i_sb - > s_fs_info ;
2016-10-20 17:47:56 +03:00
2016-10-20 00:24:47 +03:00
err = ubifs_enable_encryption ( c ) ;
if ( err )
return err ;
2016-12-13 02:27:59 +03:00
return fscrypt_ioctl_set_policy ( file , ( const void __user * ) arg ) ;
2016-10-20 17:47:56 +03:00
}
2019-03-15 23:55:03 +03:00
case FS_IOC_GET_ENCRYPTION_POLICY :
2016-12-13 02:27:59 +03:00
return fscrypt_ioctl_get_policy ( file , ( void __user * ) arg ) ;
2008-07-14 20:08:37 +04:00
2019-08-05 05:35:49 +03:00
case FS_IOC_GET_ENCRYPTION_POLICY_EX :
return fscrypt_ioctl_get_policy_ex ( file , ( void __user * ) arg ) ;
case FS_IOC_ADD_ENCRYPTION_KEY :
return fscrypt_ioctl_add_key ( file , ( void __user * ) arg ) ;
case FS_IOC_REMOVE_ENCRYPTION_KEY :
return fscrypt_ioctl_remove_key ( file , ( void __user * ) arg ) ;
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS :
return fscrypt_ioctl_remove_key_all_users ( file ,
( void __user * ) arg ) ;
case FS_IOC_GET_ENCRYPTION_KEY_STATUS :
return fscrypt_ioctl_get_key_status ( file , ( void __user * ) arg ) ;
2020-03-14 23:50:52 +03:00
case FS_IOC_GET_ENCRYPTION_NONCE :
return fscrypt_ioctl_get_nonce ( file , ( void __user * ) arg ) ;
2008-07-14 20:08:37 +04:00
default :
return - ENOTTY ;
}
}
# ifdef CONFIG_COMPAT
long ubifs_compat_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
switch ( cmd ) {
case FS_IOC32_GETFLAGS :
cmd = FS_IOC_GETFLAGS ;
break ;
case FS_IOC32_SETFLAGS :
cmd = FS_IOC_SETFLAGS ;
break ;
2016-12-19 22:12:48 +03:00
case FS_IOC_SET_ENCRYPTION_POLICY :
case FS_IOC_GET_ENCRYPTION_POLICY :
2019-08-05 05:35:49 +03:00
case FS_IOC_GET_ENCRYPTION_POLICY_EX :
case FS_IOC_ADD_ENCRYPTION_KEY :
case FS_IOC_REMOVE_ENCRYPTION_KEY :
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS :
case FS_IOC_GET_ENCRYPTION_KEY_STATUS :
2020-03-14 23:50:52 +03:00
case FS_IOC_GET_ENCRYPTION_NONCE :
2016-12-19 22:12:48 +03:00
break ;
2008-07-14 20:08:37 +04:00
default :
return - ENOIOCTLCMD ;
}
return ubifs_ioctl ( file , cmd , ( unsigned long ) compat_ptr ( arg ) ) ;
}
# endif