Skip to content

Commit 7832e12

Browse files
fs/ntfs3: Add support /proc/fs/ntfs3/<dev>/volinfo and /proc/fs/ntfs3/<dev>/label
Metafile /proc/fs/ntfs3/<dev>/label allows to read/write current ntfs label. Signed-off-by: Konstantin Komarov <[email protected]>
1 parent d5ca773 commit 7832e12

File tree

3 files changed

+195
-2
lines changed

3 files changed

+195
-2
lines changed

fs/ntfs3/fsntfs.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/buffer_head.h>
1010
#include <linux/fs.h>
1111
#include <linux/kernel.h>
12+
#include <linux/nls.h>
1213

1314
#include "debug.h"
1415
#include "ntfs.h"
@@ -2619,3 +2620,60 @@ bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *fname)
26192620
return !name_has_forbidden_chars(fname) &&
26202621
!is_reserved_name(sbi, fname);
26212622
}
2623+
2624+
/*
2625+
* ntfs_set_label - updates current ntfs label.
2626+
*/
2627+
int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
2628+
{
2629+
int err;
2630+
struct ATTRIB *attr;
2631+
struct ntfs_inode *ni = sbi->volume.ni;
2632+
const u8 max_ulen = 0x80; /* TODO: use attrdef to get maximum length */
2633+
/* Allocate PATH_MAX bytes. */
2634+
struct cpu_str *uni = __getname();
2635+
2636+
if (!uni)
2637+
return -ENOMEM;
2638+
2639+
err = ntfs_nls_to_utf16(sbi, label, len, uni, (PATH_MAX - 2) / 2,
2640+
UTF16_LITTLE_ENDIAN);
2641+
if (err < 0)
2642+
goto out;
2643+
2644+
if (uni->len > max_ulen) {
2645+
ntfs_warn(sbi->sb, "new label is too long");
2646+
err = -EFBIG;
2647+
goto out;
2648+
}
2649+
2650+
ni_lock(ni);
2651+
2652+
/* Ignore any errors. */
2653+
ni_remove_attr(ni, ATTR_LABEL, NULL, 0, false, NULL);
2654+
2655+
err = ni_insert_resident(ni, uni->len * sizeof(u16), ATTR_LABEL, NULL,
2656+
0, &attr, NULL, NULL);
2657+
if (err < 0)
2658+
goto unlock_out;
2659+
2660+
/* write new label in on-disk struct. */
2661+
memcpy(resident_data(attr), uni->name, uni->len * sizeof(u16));
2662+
2663+
/* update cached value of current label. */
2664+
if (len >= ARRAY_SIZE(sbi->volume.label))
2665+
len = ARRAY_SIZE(sbi->volume.label) - 1;
2666+
memcpy(sbi->volume.label, label, len);
2667+
sbi->volume.label[len] = 0;
2668+
mark_inode_dirty_sync(&ni->vfs_inode);
2669+
2670+
unlock_out:
2671+
ni_unlock(ni);
2672+
2673+
if (!err)
2674+
err = _ni_write_inode(&ni->vfs_inode, 0);
2675+
2676+
out:
2677+
__putname(uni);
2678+
return err;
2679+
}

fs/ntfs3/ntfs_fs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ struct ntfs_sb_info {
276276
__le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY.
277277
u8 major_ver;
278278
u8 minor_ver;
279-
char label[65];
279+
char label[256];
280280
bool real_dirty; // Real fs state.
281281
} volume;
282282

@@ -286,7 +286,6 @@ struct ntfs_sb_info {
286286
struct ntfs_inode *ni;
287287
u32 next_id;
288288
u64 next_off;
289-
290289
__le32 def_security_id;
291290
} security;
292291

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

315314
struct ntfs_mount_options *options;
316315
struct ratelimit_state msg_ratelimit;
316+
struct proc_dir_entry *procdir;
317317
};
318318

319319
/* 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);
651651
int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
652652
bool trim);
653653
bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name);
654+
int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len);
654655

655656
/* Globals from index.c */
656657
int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit);

fs/ntfs3/super.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <linux/minmax.h>
5858
#include <linux/module.h>
5959
#include <linux/nls.h>
60+
#include <linux/proc_fs.h>
6061
#include <linux/seq_file.h>
6162
#include <linux/statfs.h>
6263

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

445+
#ifdef CONFIG_PROC_FS
446+
static struct proc_dir_entry *proc_info_root;
447+
448+
/*
449+
* ntfs3_volinfo:
450+
*
451+
* The content of /proc/fs/ntfs3/<dev>/volinfo
452+
*
453+
* ntfs3.1
454+
* cluster size
455+
* number of clusters
456+
*/
457+
static int ntfs3_volinfo(struct seq_file *m, void *o)
458+
{
459+
struct super_block *sb = m->private;
460+
struct ntfs_sb_info *sbi = sb->s_fs_info;
461+
462+
seq_printf(m, "ntfs%d.%d\n%u\n%zu\n", sbi->volume.major_ver,
463+
sbi->volume.minor_ver, sbi->cluster_size,
464+
sbi->used.bitmap.nbits);
465+
466+
return 0;
467+
}
468+
469+
static int ntfs3_volinfo_open(struct inode *inode, struct file *file)
470+
{
471+
return single_open(file, ntfs3_volinfo, pde_data(inode));
472+
}
473+
474+
/* read /proc/fs/ntfs3/<dev>/label */
475+
static int ntfs3_label_show(struct seq_file *m, void *o)
476+
{
477+
struct super_block *sb = m->private;
478+
struct ntfs_sb_info *sbi = sb->s_fs_info;
479+
480+
seq_printf(m, "%s\n", sbi->volume.label);
481+
482+
return 0;
483+
}
484+
485+
/* write /proc/fs/ntfs3/<dev>/label */
486+
static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer,
487+
size_t count, loff_t *ppos)
488+
{
489+
int err;
490+
struct super_block *sb = pde_data(file_inode(file));
491+
struct ntfs_sb_info *sbi = sb->s_fs_info;
492+
ssize_t ret = count;
493+
u8 *label = kmalloc(count, GFP_NOFS);
494+
495+
if (!label)
496+
return -ENOMEM;
497+
498+
if (copy_from_user(label, buffer, ret)) {
499+
ret = -EFAULT;
500+
goto out;
501+
}
502+
while (ret > 0 && label[ret - 1] == '\n')
503+
ret -= 1;
504+
505+
err = ntfs_set_label(sbi, label, ret);
506+
507+
if (err < 0) {
508+
ntfs_err(sb, "failed (%d) to write label", err);
509+
ret = err;
510+
goto out;
511+
}
512+
513+
*ppos += count;
514+
ret = count;
515+
out:
516+
kfree(label);
517+
return ret;
518+
}
519+
520+
static int ntfs3_label_open(struct inode *inode, struct file *file)
521+
{
522+
return single_open(file, ntfs3_label_show, pde_data(inode));
523+
}
524+
525+
static const struct proc_ops ntfs3_volinfo_fops = {
526+
.proc_read = seq_read,
527+
.proc_lseek = seq_lseek,
528+
.proc_release = single_release,
529+
.proc_open = ntfs3_volinfo_open,
530+
};
531+
532+
static const struct proc_ops ntfs3_label_fops = {
533+
.proc_read = seq_read,
534+
.proc_lseek = seq_lseek,
535+
.proc_release = single_release,
536+
.proc_open = ntfs3_label_open,
537+
.proc_write = ntfs3_label_write,
538+
};
539+
540+
#endif
541+
444542
static struct kmem_cache *ntfs_inode_cachep;
445543

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

616+
#ifdef CONFIG_PROC_FS
617+
// Remove /proc/fs/ntfs3/..
618+
if (sbi->procdir) {
619+
remove_proc_entry("label", sbi->procdir);
620+
remove_proc_entry("volinfo", sbi->procdir);
621+
remove_proc_entry(sb->s_id, proc_info_root);
622+
sbi->procdir = NULL;
623+
}
624+
#endif
625+
518626
/* Mark rw ntfs as clear, if possible. */
519627
ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);
520628

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

1547+
#ifdef CONFIG_PROC_FS
1548+
/* Create /proc/fs/ntfs3/.. */
1549+
if (proc_info_root) {
1550+
struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root);
1551+
if (e) {
1552+
proc_create_data("volinfo", S_IFREG | S_IRUGO, e,
1553+
&ntfs3_volinfo_fops, sb);
1554+
proc_create_data("label", S_IFREG | S_IRUGO | S_IWUGO,
1555+
e, &ntfs3_label_fops, sb);
1556+
sbi->procdir = e;
1557+
}
1558+
}
1559+
#endif
1560+
14391561
return 0;
14401562

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

1755+
1756+
#ifdef CONFIG_PROC_FS
1757+
/* Create "/proc/fs/ntfs3" */
1758+
proc_info_root = proc_mkdir("fs/ntfs3", NULL);
1759+
#endif
1760+
16331761
err = ntfs3_init_bitmap();
16341762
if (err)
16351763
return err;
@@ -1661,6 +1789,12 @@ static void __exit exit_ntfs_fs(void)
16611789
kmem_cache_destroy(ntfs_inode_cachep);
16621790
unregister_filesystem(&ntfs_fs_type);
16631791
ntfs3_exit_bitmap();
1792+
1793+
#ifdef CONFIG_PROC_FS
1794+
if (proc_info_root)
1795+
remove_proc_entry("fs/ntfs3", NULL);
1796+
#endif
1797+
16641798
}
16651799

16661800
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)