2017-12-21 12:56:55

by chenchacha

[permalink] [raw]
Subject: [PATCH 0/2] fs: fat: add ioctl to modify fat filesystem partion volume label

The FAT filesystem partition volume label can be read with
FAT_IOCTL_GET_VOLUME_LABEL and written with FAT_IOCTL_SET_VOLUME_LABEL.

v2:
1. add filesystem version check.
2. add diretory permissions check.
3. add volume label string check.
4. fixed part of return value.
5. fixed some indent issue.
6. remove sync_dirty_buffer().

Chen Guanqiao (2):
fs: fat: add fat filesystem partition volume label in local structure
fs: fat: add ioctl method in fat filesystem driver

fs/fat/fat.h | 1 +
fs/fat/file.c | 103 ++++++++++++++++++++++++++++++++++++++++++
fs/fat/inode.c | 15 ++++--
include/uapi/linux/msdos_fs.h | 2 +
4 files changed, 118 insertions(+), 3 deletions(-)

--
2.15.1




2017-12-21 12:57:07

by chenchacha

[permalink] [raw]
Subject: [PATCH 2/2] fs: fat: add ioctl method in fat filesystem driver

Signed-off-by: Chen Guanqiao <[email protected]>
---
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



2017-12-21 13:04:09

by chenchacha

[permalink] [raw]
Subject: [PATCH 1/2] fs: fat: add fat filesystem partition volume label in local structure

Signed-off-by: Chen Guanqiao <[email protected]>
---
fs/fat/fat.h | 1 +
fs/fat/inode.c | 15 ++++++++++++---
include/uapi/linux/msdos_fs.h | 2 ++
3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 8fc1093da47d..204012c94421 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -86,6 +86,7 @@ struct msdos_sb_info {
int dir_per_block; /* dir entries per block */
int dir_per_block_bits; /* log2(dir_per_block) */
unsigned int vol_id; /*volume ID*/
+ char vol_label[11]; /*volume label*/

int fatent_shift;
const struct fatent_operations *fatent_ops;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 20a0a89eaca5..a97b6314ef33 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -45,12 +45,14 @@ struct fat_bios_param_block {

u8 fat16_state;
u32 fat16_vol_id;
+ u8 fat16_vol_label[11];

u32 fat32_length;
u32 fat32_root_cluster;
u16 fat32_info_sector;
u8 fat32_state;
u32 fat32_vol_id;
+ u8 fat32_vol_label[11];
};

static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
@@ -1460,12 +1462,16 @@ static int fat_read_bpb(struct super_block *sb, struct fat_boot_sector *b,

bpb->fat16_state = b->fat16.state;
bpb->fat16_vol_id = get_unaligned_le32(b->fat16.vol_id);
+ memcpy(bpb->fat16_vol_label, b->fat16.vol_label,
+ sizeof(bpb->fat16_vol_label));

bpb->fat32_length = le32_to_cpu(b->fat32.length);
bpb->fat32_root_cluster = le32_to_cpu(b->fat32.root_cluster);
bpb->fat32_info_sector = le16_to_cpu(b->fat32.info_sector);
bpb->fat32_state = b->fat32.state;
bpb->fat32_vol_id = get_unaligned_le32(b->fat32.vol_id);
+ memcpy(bpb->fat32_vol_label, b->fat32.vol_label,
+ sizeof(bpb->fat32_vol_label));

/* Validate this looks like a FAT filesystem BPB */
if (!bpb->fat_reserved) {
@@ -1723,11 +1729,14 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
brelse(fsinfo_bh);
}

- /* interpret volume ID as a little endian 32 bit integer */
- if (sbi->fat_bits == 32)
+ /* interpret volume ID and label as a little endian 32 bit integer */
+ if (sbi->fat_bits == 32) {
sbi->vol_id = bpb.fat32_vol_id;
- else /* fat 16 or 12 */
+ memcpy(sbi->vol_label, bpb.fat32_vol_label, sizeof(sbi->vol_label));
+ } else { /* fat 16 or 12 */
sbi->vol_id = bpb.fat16_vol_id;
+ memcpy(sbi->vol_label, bpb.fat16_vol_label, sizeof(sbi->vol_label));
+ }

sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
diff --git a/include/uapi/linux/msdos_fs.h b/include/uapi/linux/msdos_fs.h
index a45d0754102e..90d2d6f3d908 100644
--- a/include/uapi/linux/msdos_fs.h
+++ b/include/uapi/linux/msdos_fs.h
@@ -107,6 +107,8 @@ struct __fat_dirent {
#define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32)
/*Android kernel has used 0x12, so we use 0x13*/
#define FAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x13, __u32)
+#define FAT_IOCTL_GET_VOLUME_LABEL _IOR('r', 0x14, __u8[11])
+#define FAT_IOCTL_SET_VOLUME_LABEL _IOW('r', 0x15, __u8[11])

struct fat_boot_sector {
__u8 ignored[3]; /* Boot strap short or near jump */
--
2.15.1

2017-12-21 19:25:27

by OGAWA Hirofumi

[permalink] [raw]
Subject: Re: [PATCH 0/2] fs: fat: add ioctl to modify fat filesystem partion volume label

Chen Guanqiao <[email protected]> writes:

> The FAT filesystem partition volume label can be read with
> FAT_IOCTL_GET_VOLUME_LABEL and written with FAT_IOCTL_SET_VOLUME_LABEL.
>
> v2:
> 1. add filesystem version check.
> 2. add diretory permissions check.
> 3. add volume label string check.
> 4. fixed part of return value.
> 5. fixed some indent issue.
> 6. remove sync_dirty_buffer().

As I said in previous email, those vol_label should be matching with
volume label in root directory, right? So I think handling only boot
sector's vol_label would not work as expected.

Does this really works as expected?

E.g. suspected test case is,

1) write label on windows
2) modify label on linux
3) read modified label on windows

Thanks.
--
OGAWA Hirofumi <[email protected]>