2005-04-17 02:20:36 +04:00
/*
* linux / fs / fat / file . c
*
* Written 1992 , 1993 by Werner Almesberger
*
* regular file handling primitives for fat - based filesystems
*/
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2010-05-17 03:13:47 +04:00
# include <linux/compat.h>
2008-02-16 01:37:46 +03:00
# include <linux/mount.h>
2006-09-29 13:00:03 +04:00
# include <linux/blkdev.h>
2015-05-23 00:13:32 +03:00
# include <linux/backing-dev.h>
2008-07-01 17:01:28 +04:00
# include <linux/fsnotify.h>
# include <linux/security.h>
2008-11-06 23:53:46 +03:00
# include "fat.h"
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
static int fat_ioctl_get_attributes ( struct inode * inode , u32 __user * user_attr )
{
u32 attr ;
mutex_lock ( & inode - > i_mutex ) ;
attr = fat_make_attrs ( inode ) ;
mutex_unlock ( & inode - > i_mutex ) ;
return put_user ( attr , user_attr ) ;
}
static int fat_ioctl_set_attributes ( struct file * file , u32 __user * user_attr )
2005-04-17 02:20:36 +04:00
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) ;
2005-04-17 02:20:36 +04:00
struct msdos_sb_info * sbi = MSDOS_SB ( inode - > i_sb ) ;
2009-06-08 16:38:31 +04:00
int is_dir = S_ISDIR ( inode - > i_mode ) ;
u32 attr , oldattr ;
struct iattr ia ;
int err ;
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
err = get_user ( attr , user_attr ) ;
if ( err )
goto out ;
2005-04-17 02:20:36 +04:00
2011-11-23 20:57:51 +04:00
err = mnt_want_write_file ( file ) ;
2009-06-08 16:38:31 +04:00
if ( err )
2012-06-12 18:20:31 +04:00
goto out ;
mutex_lock ( & inode - > i_mutex ) ;
2009-06-08 16:38:31 +04:00
/*
* ATTR_VOLUME and ATTR_DIR cannot be changed ; this also
* prevents the user from turning us into a VFAT
* longname entry . Also , we obviously can ' t set
* any of the NTFS attributes in the high 24 bits .
*/
attr & = 0xff & ~ ( ATTR_VOLUME | ATTR_DIR ) ;
/* Merge in ATTR_VOLUME and ATTR_DIR */
attr | = ( MSDOS_I ( inode ) - > i_attrs & ATTR_VOLUME ) |
( is_dir ? ATTR_DIR : 0 ) ;
oldattr = fat_make_attrs ( inode ) ;
/* Equivalent to a chmod() */
ia . ia_valid = ATTR_MODE | ATTR_CTIME ;
ia . ia_ctime = current_fs_time ( inode - > i_sb ) ;
if ( is_dir )
ia . ia_mode = fat_make_mode ( sbi , attr , S_IRWXUGO ) ;
else {
ia . ia_mode = fat_make_mode ( sbi , attr ,
S_IRUGO | S_IWUGO | ( inode - > i_mode & S_IXUGO ) ) ;
}
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
/* The root directory has no attributes */
if ( inode - > i_ino = = MSDOS_ROOT_INO & & attr ! = ATTR_DIR ) {
err = - EINVAL ;
2012-06-12 18:20:31 +04:00
goto out_unlock_inode ;
2005-04-17 02:20:36 +04:00
}
2009-06-08 16:38:31 +04:00
if ( sbi - > options . sys_immutable & &
( ( attr | oldattr ) & ATTR_SYS ) & &
! capable ( CAP_LINUX_IMMUTABLE ) ) {
err = - EPERM ;
2012-06-12 18:20:31 +04:00
goto out_unlock_inode ;
2009-06-08 16:38:31 +04:00
}
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
/*
* The security check is questionable . . . We single
* out the RO attribute for checking by the security
* module , just because it maps to a file mode .
*/
err = security_inode_setattr ( file - > f_path . dentry , & ia ) ;
if ( err )
2012-06-12 18:20:31 +04:00
goto out_unlock_inode ;
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
/* This MUST be done before doing anything irreversible... */
err = fat_setattr ( file - > f_path . dentry , & ia ) ;
if ( err )
2012-06-12 18:20:31 +04:00
goto out_unlock_inode ;
2009-06-08 16:38:31 +04:00
fsnotify_change ( file - > f_path . dentry , ia . ia_valid ) ;
if ( sbi - > options . sys_immutable ) {
if ( attr & ATTR_SYS )
inode - > i_flags | = S_IMMUTABLE ;
else
2011-05-31 14:38:07 +04:00
inode - > i_flags & = ~ S_IMMUTABLE ;
2009-06-08 16:38:31 +04:00
}
2005-04-17 02:20:36 +04:00
2009-06-08 16:38:31 +04:00
fat_save_attrs ( inode , attr ) ;
mark_inode_dirty ( inode ) ;
out_unlock_inode :
mutex_unlock ( & inode - > i_mutex ) ;
2012-06-12 18:20:31 +04:00
mnt_drop_write_file ( file ) ;
2009-06-08 16:38:31 +04:00
out :
return err ;
}
2005-04-17 02:20:36 +04:00
fatfs: add FAT_IOCTL_GET_VOLUME_ID
This patch, originally from Android kernel, adds vfat ioctl command
FAT_IOCTL_GET_VOLUME_ID, with this command we can get the vfat volume ID
using following code:
ioctl(fd, FAT_IOCTL_GET_VOLUME_ID, &volume_ID)
This patch is a modified version of the patch by Mike Lockwood, with
changes from Dmitry Pervushin, who noticed the original patch makes some
volume IDs abiguous with error returns: for example, if volume id is
0xFFFFFDAD, that matches -ENOIOCTLCMD, we get "FFFFFFFF" from the user
space.
So add a parameter to ioctl to get the correct volume ID.
Android uses vfat volume ID to identify different sd card, when a new sd
card is inserted to device, android can scan the media on it and pop up
new contents.
Signed-off-by: Bintian Wang <bintian.wang@linaro.org>
Cc: dmitry pervushin <dpervushin@gmail.com>
Cc: Mike Lockwood <lockwood@android.com>
Cc: Colin Cross <ccross@android.com>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Sean McNeil <sean@mcneil.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-07-09 03:00:46 +04:00
static int fat_ioctl_get_volume_id ( struct inode * inode , u32 __user * user_attr )
{
struct msdos_sb_info * sbi = MSDOS_SB ( inode - > i_sb ) ;
return put_user ( sbi - > vol_id , user_attr ) ;
}
2010-05-17 03:13:47 +04:00
long fat_generic_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( filp ) ;
2005-04-17 02:20:36 +04:00
u32 __user * user_attr = ( u32 __user * ) arg ;
switch ( cmd ) {
case FAT_IOCTL_GET_ATTRIBUTES :
2009-06-08 16:38:31 +04:00
return fat_ioctl_get_attributes ( inode , user_attr ) ;
2005-04-17 02:20:36 +04:00
case FAT_IOCTL_SET_ATTRIBUTES :
2009-06-08 16:38:31 +04:00
return fat_ioctl_set_attributes ( filp , user_attr ) ;
fatfs: add FAT_IOCTL_GET_VOLUME_ID
This patch, originally from Android kernel, adds vfat ioctl command
FAT_IOCTL_GET_VOLUME_ID, with this command we can get the vfat volume ID
using following code:
ioctl(fd, FAT_IOCTL_GET_VOLUME_ID, &volume_ID)
This patch is a modified version of the patch by Mike Lockwood, with
changes from Dmitry Pervushin, who noticed the original patch makes some
volume IDs abiguous with error returns: for example, if volume id is
0xFFFFFDAD, that matches -ENOIOCTLCMD, we get "FFFFFFFF" from the user
space.
So add a parameter to ioctl to get the correct volume ID.
Android uses vfat volume ID to identify different sd card, when a new sd
card is inserted to device, android can scan the media on it and pop up
new contents.
Signed-off-by: Bintian Wang <bintian.wang@linaro.org>
Cc: dmitry pervushin <dpervushin@gmail.com>
Cc: Mike Lockwood <lockwood@android.com>
Cc: Colin Cross <ccross@android.com>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Sean McNeil <sean@mcneil.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-07-09 03:00:46 +04:00
case FAT_IOCTL_GET_VOLUME_ID :
return fat_ioctl_get_volume_id ( inode , user_attr ) ;
2005-04-17 02:20:36 +04:00
default :
return - ENOTTY ; /* Inappropriate ioctl for device */
}
}
2010-05-17 03:13:47 +04:00
# ifdef CONFIG_COMPAT
static long fat_generic_compat_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
{
return fat_generic_ioctl ( filp , cmd , ( unsigned long ) compat_ptr ( arg ) ) ;
}
# endif
2006-09-29 13:00:03 +04:00
static int fat_file_release ( struct inode * inode , struct file * filp )
{
if ( ( filp - > f_mode & FMODE_WRITE ) & &
MSDOS_SB ( inode - > i_sb ) - > options . flush ) {
fat_flush_inodes ( inode - > i_sb , inode , NULL ) ;
2009-07-09 16:52:32 +04:00
congestion_wait ( BLK_RW_ASYNC , HZ / 10 ) ;
2006-09-29 13:00:03 +04:00
}
return 0 ;
}
2011-07-17 04:44:56 +04:00
int fat_file_fsync ( struct file * filp , loff_t start , loff_t end , int datasync )
2009-06-07 21:44:36 +04:00
{
2010-05-26 19:53:25 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2009-06-07 21:44:36 +04:00
int res , err ;
2011-07-17 04:44:56 +04:00
res = generic_file_fsync ( filp , start , end , datasync ) ;
2009-06-07 21:44:36 +04:00
err = sync_mapping_buffers ( MSDOS_SB ( inode - > i_sb ) - > fat_inode - > i_mapping ) ;
return res ? res : err ;
}
2006-03-28 13:56:42 +04:00
const struct file_operations fat_file_operations = {
2005-04-17 02:20:36 +04:00
. llseek = generic_file_llseek ,
2014-04-02 22:33:16 +04:00
. read_iter = generic_file_read_iter ,
2014-04-03 11:17:43 +04:00
. write_iter = generic_file_write_iter ,
2005-04-17 02:20:36 +04:00
. mmap = generic_file_mmap ,
2006-09-29 13:00:03 +04:00
. release = fat_file_release ,
2010-05-17 03:13:47 +04:00
. unlocked_ioctl = fat_generic_ioctl ,
# ifdef CONFIG_COMPAT
. compat_ioctl = fat_generic_compat_ioctl ,
# endif
2009-06-07 21:44:36 +04:00
. fsync = fat_file_fsync ,
2007-06-01 13:49:19 +04:00
. splice_read = generic_file_splice_read ,
2005-04-17 02:20:36 +04:00
} ;
2006-01-08 12:02:13 +03:00
static int fat_cont_expand ( struct inode * inode , loff_t size )
{
struct address_space * mapping = inode - > i_mapping ;
loff_t start = inode - > i_size , count = size - inode - > i_size ;
int err ;
err = generic_cont_expand_simple ( inode , size ) ;
if ( err )
goto out ;
inode - > i_ctime = inode - > i_mtime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
2009-08-17 19:00:02 +04:00
if ( IS_SYNC ( inode ) ) {
int err2 ;
/*
* Opencode syncing since we don ' t have a file open to use
* standard fsync path .
*/
err = filemap_fdatawrite_range ( mapping , start ,
start + count - 1 ) ;
err2 = sync_mapping_buffers ( mapping ) ;
if ( ! err )
err = err2 ;
err2 = write_inode_now ( inode , 1 ) ;
if ( ! err )
err = err2 ;
if ( ! err ) {
err = filemap_fdatawait_range ( mapping , start ,
start + count - 1 ) ;
}
}
2006-01-08 12:02:13 +03:00
out :
return err ;
}
2005-04-17 02:20:36 +04:00
/* Free all clusters after the skip'th cluster. */
static int fat_free ( struct inode * inode , int skip )
{
struct super_block * sb = inode - > i_sb ;
int err , wait , free_start , i_start , i_logstart ;
if ( MSDOS_I ( inode ) - > i_start = = 0 )
return 0 ;
2006-02-03 14:04:44 +03:00
fat_cache_inval_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
wait = IS_DIRSYNC ( inode ) ;
2006-02-03 14:04:44 +03:00
i_start = free_start = MSDOS_I ( inode ) - > i_start ;
i_logstart = MSDOS_I ( inode ) - > i_logstart ;
/* First, we write the new file size. */
if ( ! skip ) {
MSDOS_I ( inode ) - > i_start = 0 ;
MSDOS_I ( inode ) - > i_logstart = 0 ;
}
MSDOS_I ( inode ) - > i_attrs | = ATTR_ARCH ;
inode - > i_ctime = inode - > i_mtime = CURRENT_TIME_SEC ;
if ( wait ) {
err = fat_sync_inode ( inode ) ;
if ( err ) {
MSDOS_I ( inode ) - > i_start = i_start ;
MSDOS_I ( inode ) - > i_logstart = i_logstart ;
return err ;
}
} else
mark_inode_dirty ( inode ) ;
/* Write a new EOF, and get the remaining cluster chain for freeing. */
2005-04-17 02:20:36 +04:00
if ( skip ) {
struct fat_entry fatent ;
int ret , fclus , dclus ;
ret = fat_get_cluster ( inode , skip - 1 , & fclus , & dclus ) ;
if ( ret < 0 )
return ret ;
else if ( ret = = FAT_ENT_EOF )
return 0 ;
fatent_init ( & fatent ) ;
ret = fat_ent_read ( inode , & fatent , dclus ) ;
if ( ret = = FAT_ENT_EOF ) {
fatent_brelse ( & fatent ) ;
return 0 ;
} else if ( ret = = FAT_ENT_FREE ) {
2009-06-03 21:34:22 +04:00
fat_fs_error ( sb ,
2005-04-17 02:20:36 +04:00
" %s: invalid cluster chain (i_pos %lld) " ,
2008-04-30 11:55:09 +04:00
__func__ , MSDOS_I ( inode ) - > i_pos ) ;
2005-04-17 02:20:36 +04:00
ret = - EIO ;
} else if ( ret > 0 ) {
err = fat_ent_write ( inode , & fatent , FAT_ENT_EOF , wait ) ;
if ( err )
ret = err ;
}
fatent_brelse ( & fatent ) ;
if ( ret < 0 )
return ret ;
free_start = ret ;
}
inode - > i_blocks = skip < < ( MSDOS_SB ( sb ) - > cluster_bits - 9 ) ;
/* Freeing the remained cluster chain */
return fat_free_clusters ( inode , free_start ) ;
}
2010-05-26 19:05:38 +04:00
void fat_truncate_blocks ( struct inode * inode , loff_t offset )
2005-04-17 02:20:36 +04:00
{
2008-05-30 03:14:05 +04:00
struct msdos_sb_info * sbi = MSDOS_SB ( inode - > i_sb ) ;
2005-04-17 02:20:36 +04:00
const unsigned int cluster_size = sbi - > cluster_size ;
int nr_clusters ;
/*
* This protects against truncating a file bigger than it was then
* trying to write into the hole .
*/
2010-05-26 19:05:38 +04:00
if ( MSDOS_I ( inode ) - > mmu_private > offset )
MSDOS_I ( inode ) - > mmu_private = offset ;
2005-04-17 02:20:36 +04:00
2010-05-26 19:05:38 +04:00
nr_clusters = ( offset + ( cluster_size - 1 ) ) > > sbi - > cluster_bits ;
2005-04-17 02:20:36 +04:00
fat_free ( inode , nr_clusters ) ;
2006-09-29 13:00:03 +04:00
fat_flush_inodes ( inode - > i_sb , inode , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-16 12:19:28 +03:00
int fat_getattr ( struct vfsmount * mnt , struct dentry * dentry , struct kstat * stat )
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2006-11-16 12:19:28 +03:00
generic_fillattr ( inode , stat ) ;
stat - > blksize = MSDOS_SB ( inode - > i_sb ) - > cluster_size ;
2013-04-30 03:21:11 +04:00
if ( MSDOS_SB ( inode - > i_sb ) - > options . nfs = = FAT_NFS_NOSTALE_RO ) {
/* Use i_pos for ino. This is used as fileid of nfs. */
stat - > ino = fat_i_pos_read ( MSDOS_SB ( inode - > i_sb ) , inode ) ;
}
2006-11-16 12:19:28 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( fat_getattr ) ;
2008-06-13 02:21:28 +04:00
static int fat_sanitize_mode ( const struct msdos_sb_info * sbi ,
struct inode * inode , umode_t * mode_ptr )
2008-04-28 13:16:25 +04:00
{
2011-07-26 11:21:30 +04:00
umode_t mask , perm ;
2008-04-28 13:16:25 +04:00
2008-06-13 02:21:28 +04:00
/*
* Note , the basic check is already done by a caller of
2008-11-06 23:53:54 +03:00
* ( attr - > ia_mode & ~ FAT_VALID_MODE )
2008-06-13 02:21:28 +04:00
*/
if ( S_ISREG ( inode - > i_mode ) )
2008-04-28 13:16:25 +04:00
mask = sbi - > options . fs_fmask ;
else
mask = sbi - > options . fs_dmask ;
2008-06-13 02:21:28 +04:00
perm = * mode_ptr & ~ ( S_IFMT | mask ) ;
2008-04-28 13:16:25 +04:00
/*
* Of the r and x bits , all ( subject to umask ) must be present . Of the
* w bits , either all ( subject to umask ) or none must be present .
2008-11-06 23:53:55 +03:00
*
* If fat_mode_can_hold_ro ( inode ) is false , can ' t change w bits .
2008-04-28 13:16:25 +04:00
*/
2008-06-13 02:21:28 +04:00
if ( ( perm & ( S_IRUGO | S_IXUGO ) ) ! = ( inode - > i_mode & ( S_IRUGO | S_IXUGO ) ) )
2008-04-28 13:16:25 +04:00
return - EPERM ;
2008-11-06 23:53:55 +03:00
if ( fat_mode_can_hold_ro ( inode ) ) {
if ( ( perm & S_IWUGO ) & & ( ( perm & S_IWUGO ) ! = ( S_IWUGO & ~ mask ) ) )
return - EPERM ;
} else {
if ( ( perm & S_IWUGO ) ! = ( S_IWUGO & ~ mask ) )
return - EPERM ;
}
2008-04-28 13:16:25 +04:00
2008-06-13 02:21:28 +04:00
* mode_ptr & = S_IFMT | perm ;
2008-04-28 13:16:25 +04:00
return 0 ;
}
2008-04-28 13:16:26 +04:00
static int fat_allow_set_time ( struct msdos_sb_info * sbi , struct inode * inode )
{
2011-07-26 11:21:30 +04:00
umode_t allow_utime = sbi - > options . allow_utime ;
2008-04-28 13:16:26 +04:00
2012-02-08 04:25:39 +04:00
if ( ! uid_eq ( current_fsuid ( ) , inode - > i_uid ) ) {
2008-04-28 13:16:26 +04:00
if ( in_group_p ( inode - > i_gid ) )
allow_utime > > = 3 ;
if ( allow_utime & MAY_WRITE )
return 1 ;
}
/* use a default check */
return 0 ;
}
2008-08-02 08:59:37 +04:00
# define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
2008-11-06 23:53:54 +03:00
/* valid file mode bits */
# define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
2008-08-02 08:59:37 +04:00
2008-04-28 13:16:25 +04:00
int fat_setattr ( struct dentry * dentry , struct iattr * attr )
{
struct msdos_sb_info * sbi = MSDOS_SB ( dentry - > d_sb ) ;
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2008-04-28 13:16:26 +04:00
unsigned int ia_valid ;
2008-11-06 23:53:55 +03:00
int error ;
2008-04-28 13:16:25 +04:00
2008-04-28 13:16:26 +04:00
/* Check for setting the inode time. */
ia_valid = attr - > ia_valid ;
2008-08-02 08:59:37 +04:00
if ( ia_valid & TIMES_SET_FLAGS ) {
2008-04-28 13:16:26 +04:00
if ( fat_allow_set_time ( sbi , inode ) )
2008-08-02 08:59:37 +04:00
attr - > ia_valid & = ~ TIMES_SET_FLAGS ;
2008-04-28 13:16:26 +04:00
}
2008-04-28 13:16:25 +04:00
error = inode_change_ok ( inode , attr ) ;
2008-04-28 13:16:26 +04:00
attr - > ia_valid = ia_valid ;
2008-04-28 13:16:25 +04:00
if ( error ) {
if ( sbi - > options . quiet )
error = 0 ;
goto out ;
}
2008-06-13 02:21:28 +04:00
2010-06-04 13:30:03 +04:00
/*
* Expand the file . Since inode_setattr ( ) updates - > i_size
* before calling the - > truncate ( ) , but FAT needs to fill the
* hole before it . XXX : this is no longer true with new truncate
* sequence .
*/
if ( attr - > ia_valid & ATTR_SIZE ) {
2011-06-24 22:29:45 +04:00
inode_dio_wait ( inode ) ;
2010-06-04 13:30:03 +04:00
if ( attr - > ia_size > inode - > i_size ) {
error = fat_cont_expand ( inode , attr - > ia_size ) ;
if ( error | | attr - > ia_valid = = ATTR_SIZE )
goto out ;
attr - > ia_valid & = ~ ATTR_SIZE ;
}
}
2008-04-28 13:16:25 +04:00
if ( ( ( attr - > ia_valid & ATTR_UID ) & &
2012-02-08 04:25:39 +04:00
( ! uid_eq ( attr - > ia_uid , sbi - > options . fs_uid ) ) ) | |
2008-04-28 13:16:25 +04:00
( ( attr - > ia_valid & ATTR_GID ) & &
2012-02-08 04:25:39 +04:00
( ! gid_eq ( attr - > ia_gid , sbi - > options . fs_gid ) ) ) | |
2008-04-28 13:16:26 +04:00
( ( attr - > ia_valid & ATTR_MODE ) & &
2008-11-06 23:53:54 +03:00
( attr - > ia_mode & ~ FAT_VALID_MODE ) ) )
2008-04-28 13:16:25 +04:00
error = - EPERM ;
if ( error ) {
if ( sbi - > options . quiet )
error = 0 ;
goto out ;
}
2008-06-13 02:21:28 +04:00
/*
* We don ' t return - EPERM here . Yes , strange , but this is too
* old behavior .
*/
if ( attr - > ia_valid & ATTR_MODE ) {
if ( fat_sanitize_mode ( sbi , inode , & attr - > ia_mode ) < 0 )
attr - > ia_valid & = ~ ATTR_MODE ;
}
2008-04-28 13:16:25 +04:00
2010-05-26 19:05:38 +04:00
if ( attr - > ia_valid & ATTR_SIZE ) {
2014-12-13 03:57:26 +03:00
error = fat_block_truncate_page ( inode , attr - > ia_size ) ;
if ( error )
goto out ;
2011-06-24 22:29:40 +04:00
down_write ( & MSDOS_I ( inode ) - > truncate_lock ) ;
2010-06-04 13:30:04 +04:00
truncate_setsize ( inode , attr - > ia_size ) ;
fat_truncate_blocks ( inode , attr - > ia_size ) ;
2011-06-24 22:29:40 +04:00
up_write ( & MSDOS_I ( inode ) - > truncate_lock ) ;
2010-05-26 19:05:38 +04:00
}
2010-06-04 13:30:00 +04:00
setattr_copy ( inode , attr ) ;
2010-05-26 19:05:38 +04:00
mark_inode_dirty ( inode ) ;
2008-04-28 13:16:25 +04:00
out :
return error ;
}
EXPORT_SYMBOL_GPL ( fat_setattr ) ;
2007-02-12 11:55:38 +03:00
const struct inode_operations fat_file_inode_operations = {
2008-04-28 13:16:25 +04:00
. setattr = fat_setattr ,
2006-11-16 12:19:28 +03:00
. getattr = fat_getattr ,
2005-04-17 02:20:36 +04:00
} ;