[PATCH 10/10] fs/ntfs3: Add support /proc/fs/ntfs3/<dev>/volinfo and /proc/fs/ntfs3/<dev>/label

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Metafile /proc/fs/ntfs3/<dev>/label allows to read/write current ntfs label.

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@xxxxxxxxxxxxxxxxxxxx>
---
 fs/ntfs3/fsntfs.c  |  58 ++++++++++++++++++++
 fs/ntfs3/ntfs_fs.h |   5 +-
 fs/ntfs3/super.c   | 134 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+), 2 deletions(-)

diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
index 1c05c088d1c6..33afee0f5559 100644
--- a/fs/ntfs3/fsntfs.c
+++ b/fs/ntfs3/fsntfs.c
@@ -9,6 +9,7 @@
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/nls.h>

 #include "debug.h"
 #include "ntfs.h"
@@ -2619,3 +2620,60 @@ bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname)
     return !name_has_forbidden_chars(fname) &&
            !is_reserved_name(sbi, fname);
 }
+
+/*
+ * ntfs_set_label - updates current ntfs label.
+ */
+int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
+{
+    int err;
+    struct ATTRIB *attr;
+    struct ntfs_inode *ni = sbi->volume.ni;
+    const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */
+    /* Allocate PATH_MAX bytes. */
+    struct cpu_str *uni = __getname();
+
+    if (!uni)
+        return -ENOMEM;
+
+    err = ntfs_nls_to_utf16(sbi, label, len, uni, (PATH_MAX - 2) / 2,
+                UTF16_LITTLE_ENDIAN);
+    if (err < 0)
+        goto out;
+
+    if (uni->len > max_ulen) {
+        ntfs_warn(sbi->sb, "new label is too long");
+        err = -EFBIG;
+        goto out;
+    }
+
+    ni_lock(ni);
+
+    /* Ignore any errors. */
+    ni_remove_attr(ni, ATTR_LABEL, NULL, 0, false, NULL);
+
+    err = ni_insert_resident(ni, uni->len * sizeof(u16), ATTR_LABEL, NULL,
+                 0, &attr, NULL, NULL);
+    if (err < 0)
+        goto unlock_out;
+
+    /* write new label in on-disk struct. */
+    memcpy(resident_data(attr), uni->name, uni->len * sizeof(u16));
+
+    /* update cached value of current label. */
+    if (len >= ARRAY_SIZE(sbi->volume.label))
+        len = ARRAY_SIZE(sbi->volume.label) - 1;
+    memcpy(sbi->volume.label, label, len);
+    sbi->volume.label[len] = 0;
+    mark_inode_dirty_sync(&ni->vfs_inode);
+
+unlock_out:
+    ni_unlock(ni);
+
+    if (!err)
+        err = _ni_write_inode(&ni->vfs_inode, 0);
+
+out:
+    __putname(uni);
+    return err;
+}
\ No newline at end of file
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
index 00fa782fcada..629403ede6e5 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -276,7 +276,7 @@ struct ntfs_sb_info {
         __le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY.
         u8 major_ver;
         u8 minor_ver;
-        char label[65];
+        char label[256];
         bool real_dirty; // Real fs state.
     } volume;

@@ -286,7 +286,6 @@ struct ntfs_sb_info {
         struct ntfs_inode *ni;
         u32 next_id;
         u64 next_off;
-
         __le32 def_security_id;
     } security;

@@ -314,6 +313,7 @@ struct ntfs_sb_info {

     struct ntfs_mount_options *options;
     struct ratelimit_state msg_ratelimit;
+    struct proc_dir_entry *procdir;
 };

 /* One MFT record(usually 1024 bytes), consists of attributes. */
@@ -651,6 +651,7 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim);
 int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
            bool trim);
 bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name);
+int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len);

 /* Globals from index.c */
 int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit);
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 7ab0a79c7d84..e36769eac7de 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -57,6 +57,7 @@
 #include <linux/minmax.h>
 #include <linux/module.h>
 #include <linux/nls.h>
+#include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/statfs.h>

@@ -441,6 +442,103 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
     return 0;
 }

+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_info_root;
+
+/*
+ * ntfs3_volinfo:
+ *
+ * The content of /proc/fs/ntfs3/<dev>/volinfo
+ *
+ * ntfs3.1
+ * cluster size
+ * number of clusters
+*/
+static int ntfs3_volinfo(struct seq_file *m, void *o)
+{
+    struct super_block *sb = m->private;
+    struct ntfs_sb_info *sbi = sb->s_fs_info;
+
+    seq_printf(m, "ntfs%d.%d\n%u\n%zu\n", sbi->volume.major_ver,
+           sbi->volume.minor_ver, sbi->cluster_size,
+           sbi->used.bitmap.nbits);
+
+    return 0;
+}
+
+static int ntfs3_volinfo_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, ntfs3_volinfo, pde_data(inode));
+}
+
+/* read /proc/fs/ntfs3/<dev>/label */
+static int ntfs3_label_show(struct seq_file *m, void *o)
+{
+    struct super_block *sb = m->private;
+    struct ntfs_sb_info *sbi = sb->s_fs_info;
+
+    seq_printf(m, "%s\n", sbi->volume.label);
+
+    return 0;
+}
+
+/* write /proc/fs/ntfs3/<dev>/label */
+static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
+                 size_t count, loff_t *ppos)
+{
+    int err;
+    struct super_block *sb = pde_data(file_inode(file));
+    struct ntfs_sb_info *sbi = sb->s_fs_info;
+    ssize_t ret = count;
+    u8 *label = kmalloc(count, GFP_NOFS);
+
+    if (!label)
+        return -ENOMEM;
+
+    if (copy_from_user(label, buffer, ret)) {
+        ret = -EFAULT;
+        goto out;
+    }
+    while (ret > 0 && label[ret - 1] == '\n')
+        ret -= 1;
+
+    err = ntfs_set_label(sbi, label, ret);
+
+    if (err < 0) {
+        ntfs_err(sb, "failed (%d) to write label", err);
+        ret = err;
+        goto out;
+    }
+
+    *ppos += count;
+    ret = count;
+out:
+    kfree(label);
+    return ret;
+}
+
+static int ntfs3_label_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, ntfs3_label_show, pde_data(inode));
+}
+
+static const struct proc_ops ntfs3_volinfo_fops = {
+    .proc_read = seq_read,
+    .proc_lseek = seq_lseek,
+    .proc_release = single_release,
+    .proc_open = ntfs3_volinfo_open,
+};
+
+static const struct proc_ops ntfs3_label_fops = {
+    .proc_read = seq_read,
+    .proc_lseek = seq_lseek,
+    .proc_release = single_release,
+    .proc_open = ntfs3_label_open,
+    .proc_write = ntfs3_label_write,
+};
+
+#endif
+
 static struct kmem_cache *ntfs_inode_cachep;

 static struct inode *ntfs_alloc_inode(struct super_block *sb)
@@ -515,6 +613,16 @@ static void ntfs_put_super(struct super_block *sb)
 {
     struct ntfs_sb_info *sbi = sb->s_fs_info;

+#ifdef CONFIG_PROC_FS
+    // Remove /proc/fs/ntfs3/..
+    if (sbi->procdir) {
+        remove_proc_entry("label", sbi->procdir);
+        remove_proc_entry("volinfo", sbi->procdir);
+        remove_proc_entry(sb->s_id, proc_info_root);
+        sbi->procdir = NULL;
+    }
+#endif
+
     /* Mark rw ntfs as clear, if possible. */
     ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);

@@ -1436,6 +1544,20 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
         kfree(boot2);
     }

+#ifdef CONFIG_PROC_FS
+    /* Create /proc/fs/ntfs3/.. */
+    if (proc_info_root) {
+        struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root);
+        if (e) {
+            proc_create_data("volinfo", S_IFREG | S_IRUGO, e,
+                     &ntfs3_volinfo_fops, sb);
+            proc_create_data("label", S_IFREG | S_IRUGO | S_IWUGO,
+                     e, &ntfs3_label_fops, sb);
+            sbi->procdir = e;
+        }
+    }
+#endif
+
     return 0;

 put_inode_out:
@@ -1630,6 +1752,12 @@ static int __init init_ntfs_fs(void)
     if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
         pr_info("ntfs3: Read-only LZX/Xpress compression included\n");

+
+#ifdef CONFIG_PROC_FS
+    /* Create "/proc/fs/ntfs3" */
+    proc_info_root = proc_mkdir("fs/ntfs3", NULL);
+#endif
+
     err = ntfs3_init_bitmap();
     if (err)
         return err;
@@ -1661,6 +1789,12 @@ static void __exit exit_ntfs_fs(void)
     kmem_cache_destroy(ntfs_inode_cachep);
     unregister_filesystem(&ntfs_fs_type);
     ntfs3_exit_bitmap();
+
+#ifdef CONFIG_PROC_FS
+    if (proc_info_root)
+        remove_proc_entry("fs/ntfs3", NULL);
+#endif
+
 }

 MODULE_LICENSE("GPL");
--
2.34.1





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux