Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754210AbdLUM5H (ORCPT ); Thu, 21 Dec 2017 07:57:07 -0500 Received: from smtpbg65.qq.com ([103.7.28.233]:50784 "EHLO smtpbg65.qq.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753652AbdLUM5B (ORCPT ); Thu, 21 Dec 2017 07:57:01 -0500 X-QQ-mid: esmtp20t1513861015t9uwdd54v X-QQ-SSF: A1000000000000604H100900000000P X-QQ-FEAT: jLTfbrzLdoN0mct+COPKPC8qWIeYlaMj3J+KrxEvUmOCZXx1NaVtxZZ1eQSqh qPFvlw66bULBPbpy4pKZ4gO5KoSQnD/RiZal+HwkTUGyssM/Yk09vUFrj7cZVfoBsIa/x92 azcUgM22+2G+3fCK6bAnQiCqBo3GzhILwegcjHPg3TSgTQtNza4p89Gdhg0u0RJDdLsE4p4 KnCdD4rFhHjZIK6vaVECvPLA5D9T/E36JJnLxsc1OwyO34ZQBCDLRWy4/BKODLy687G9zJT RVfH+kTDISchHKoybje/8lYVY= X-QQ-GoodBg: 0 From: Chen Guanqiao To: hirofumi@mail.parknet.co.jp Cc: linux-kernel@vger.kernel.org, Chen Guanqiao Subject: [PATCH 2/2] fs: fat: add ioctl method in fat filesystem driver Date: Thu, 21 Dec 2017 20:56:41 +0800 Message-Id: <0e6ffce117c08d0f16faeb3fb11d641c618b2aa2.1513860624.git.chen.chenchacha@foxmail.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: References: In-Reply-To: References: X-QQ-SENDSIZE: 520 Feedback-ID: esmtp:foxmail.com:bgforeign:bgforeign3 X-QQ-Bgrelay: 1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3425 Lines: 141 Signed-off-by: Chen Guanqiao --- fs/fat/file.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/fs/fat/file.c b/fs/fat/file.c index 4724cc9ad650..c42c1e2e3e09 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -20,6 +20,25 @@ static long fat_fallocate(struct file *file, int mode, loff_t offset, loff_t len); +static int fat_check_volume_label(const char *label) +{ + int i; + + for (i=0; i<11; ++i) { + switch (label[i]) { + case 0x20: + case 'A' ... 'Z': + case '0' ... '9': + continue; + case 0: + return 0; + default: + return -EINVAL; + } + } + return -EINVAL; +} + static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) { u32 attr; @@ -121,10 +140,90 @@ static int fat_ioctl_get_volume_id(struct inode *inode, u32 __user *user_attr) return put_user(sbi->vol_id, user_attr); } +static int fat_ioctl_get_volume_label(struct inode *inode, + u8 __user *vol_label) +{ + int ret = 0; + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); + + if (copy_to_user(vol_label, sbi->vol_label, sizeof(sbi->vol_label))) + ret = -EFAULT; + + return ret; +} + +static int fat_ioctl_set_volume_label(struct file *file, + u8 __user *vol_label) +{ + int err = 0; + u8 label[11]; + struct buffer_head *bh; + struct fat_boot_sector *b; + struct inode *inode = file_inode(file); + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); + + if (copy_from_user(label, vol_label, sizeof(label))) { + err = -EFAULT; + goto out; + } + + if (fat_check_volume_label(label)) { + err = -EINVAL; + goto out; + } + + err = mnt_want_write_file(file); + if (err) + goto out; + + inode_lock(inode); + + if (sb_rdonly(inode->i_sb)) { + err = -EROFS; + goto out_unlock_inode; + } + + bh = sb_bread(inode->i_sb, 0); + if (bh == NULL) { + fat_msg(inode->i_sb, KERN_ERR, + "unable to read boot sector to write volume label"); + err = -EFAULT; + goto out_unlock_inode; + } + + b = (struct fat_boot_sector *) bh->b_data; + + if (b->fat16.signature == 0x28 || b->fat32.signature == 0x28) { + fat_msg(inode->i_sb, KERN_ERR, + "volume label supported since OS/2 1.2 and MS-DOS 4.0 " + "and higher"); + err = -EFAULT; + goto out_unlock_inode; + } + + lock_buffer(bh); + if (sbi->fat_bits == 32) + memcpy(b->fat32.vol_label, label, sizeof(label)); + else + memcpy(b->fat16.vol_label, label, sizeof(label)); + + mark_buffer_dirty(bh); + unlock_buffer(bh); + brelse(bh); + + memcpy(sbi->vol_label, label, sizeof(sbi->vol_label)); + + out_unlock_inode: + inode_unlock(inode); + out: + return err; +} + long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); u32 __user *user_attr = (u32 __user *)arg; + u8 __user *user_vol_label = (u8 __user *)arg; switch (cmd) { case FAT_IOCTL_GET_ATTRIBUTES: @@ -133,6 +232,10 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return fat_ioctl_set_attributes(filp, user_attr); case FAT_IOCTL_GET_VOLUME_ID: return fat_ioctl_get_volume_id(inode, user_attr); + case FAT_IOCTL_GET_VOLUME_LABEL: + return fat_ioctl_get_volume_label(inode, user_vol_label); + case FAT_IOCTL_SET_VOLUME_LABEL: + return fat_ioctl_set_volume_label(filp, user_vol_label); default: return -ENOTTY; /* Inappropriate ioctl for device */ } -- 2.15.1