2017-12-25 11:22:56

by chenchacha

[permalink] [raw]
Subject: [PATCH v4 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.

FAT volume label(volume name) is exactly same stored in boot sector and
data region (FAT32), root directory (FAT12, FAT16). Thus, the boot sector just
needs to be upgrade when the label writing.

v4:
1. read/write volume label from/to the location of the respective version.
2. correct volume label check reference from mkfs.fat.
3. fixed some code issue.

v3:
1. write volume label both boot sector and root directory.

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().

ChenGuanqiao (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 | 133 ++++++++++++++++++++++++++++++++++++++++++
fs/fat/inode.c | 15 ++++-
include/uapi/linux/msdos_fs.h | 2 +
4 files changed, 148 insertions(+), 3 deletions(-)

--
2.11.0



2017-12-25 11:23:11

by chenchacha

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

Signedat-off-by: ChenGuanqiao <[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 051dac1ce3be..c49ed0223bd8 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -85,6 +85,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 30c52394a7ad..e73379a41d49 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 e956704f5fb1..b4fced0988a9 100644
--- a/include/uapi/linux/msdos_fs.h
+++ b/include/uapi/linux/msdos_fs.h
@@ -106,6 +106,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.11.0


2017-12-25 11:23:13

by chenchacha

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

Signed-off-by: ChenGuanqiao <[email protected]>
---
fs/fat/file.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)

diff --git a/fs/fat/file.c b/fs/fat/file.c
index 4724cc9ad650..238c8e298930 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -15,11 +15,23 @@
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/falloc.h>
+#include <linux/ctype.h>
#include "fat.h"

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) {
+ if (islower(label[i]))
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
{
u32 attr;
@@ -121,10 +133,127 @@ 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 err = 0;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+
+ if (sbi->fat_bits == 32)
+ bh = sb_bread(sb, sbi->data_start);
+ else
+ bh = sb_bread(sb, sbi->dir_start);
+
+ if (bh == NULL) {
+ fat_msg(sb, KERN_ERR, "unable to read root directory");
+ err = -EIO;
+ goto out;
+ }
+
+ de = (struct msdos_dir_entry *)bh->b_data;
+ if (copy_to_user(vol_label, de->name, MSDOS_NAME))
+ err = -EFAULT;
+
+ brelse(bh);
+
+out:
+ return err;
+}
+
+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 msdos_dir_entry *de;
+ struct inode *inode = file_inode(file);
+ struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(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;
+
+ /* Update sector's vol_label */
+ bh = sb_bread(sb, 0);
+ if (bh == NULL) {
+ fat_msg(sb, KERN_ERR,
+ "unable to read boot sector to write volume label");
+ err = -EIO;
+ goto out_drop_file;
+ }
+
+ b = (struct fat_boot_sector *)bh->b_data;
+
+ 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);
+ err = sync_dirty_buffer(bh);
+ brelse(bh);
+ if (err)
+ goto out_drop_file;
+
+ /* updates root directory's vol_label */
+ if (sbi->fat_bits == 32)
+ bh = sb_bread(sb, sbi->data_start);
+ else
+ bh = sb_bread(sb, sbi->dir_start);
+
+ if (bh == NULL) {
+ fat_msg(sb, KERN_ERR,
+ "unable to read root directory to write volume label");
+ err = -EIO;
+ goto out_drop_file;
+ }
+
+ de = (struct msdos_dir_entry *)bh->b_data;
+ if (!(de->attr & ATTR_VOLUME)) {
+ err = -EFAULT;
+ goto out_drop_file;
+ }
+
+ lock_buffer(bh);
+ memcpy(de->name, label, sizeof(de->name));
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+ err = sync_dirty_buffer(bh);
+ brelse(bh);
+ if (err)
+ goto out_drop_file;
+
+ memcpy(sbi->vol_label, label, sizeof(sbi->vol_label));
+
+out_drop_file:
+ mnt_drop_write_file(file);
+ 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 +262,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.11.0


2017-12-26 16:17:01

by OGAWA Hirofumi

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

ChenGuanqiao <[email protected]> writes:

> +static int fat_check_volume_label(const char *label)
> +{
> + int i;
> +
> + for (i=0; i<11; ++i) {
> + if (islower(label[i]))
> + return -EINVAL;
> + }
> + return 0;
> +}

What happen if '\0' is included, or invalid chars as FAT filename?

> +static int fat_ioctl_get_volume_label(struct inode *inode,
> + u8 __user *vol_label)
> +{
> + int err = 0;
> + struct buffer_head *bh;
> + struct msdos_dir_entry *de;
> + struct super_block *sb = inode->i_sb;
> + struct msdos_sb_info *sbi = MSDOS_SB(sb);
> +
> + if (sbi->fat_bits == 32)
> + bh = sb_bread(sb, sbi->data_start);
> + else
> + bh = sb_bread(sb, sbi->dir_start);
> +
> + if (bh == NULL) {
> + fat_msg(sb, KERN_ERR, "unable to read root directory");
> + err = -EIO;
> + goto out;
> + }
> +
> + de = (struct msdos_dir_entry *)bh->b_data;

The volume label is not fixed place in root dir. You have to find
ATTR_VOLUME, but not ATTR_EXT.

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