mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
		
							parent
							
								
									d5ca773358
								
							
						
					
					
						commit
						7832e12349
					
				
					 3 changed files with 195 additions and 2 deletions
				
			
		| 
						 | 
					@ -9,6 +9,7 @@
 | 
				
			||||||
#include <linux/buffer_head.h>
 | 
					#include <linux/buffer_head.h>
 | 
				
			||||||
#include <linux/fs.h>
 | 
					#include <linux/fs.h>
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/nls.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "debug.h"
 | 
					#include "debug.h"
 | 
				
			||||||
#include "ntfs.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) &&
 | 
						return !name_has_forbidden_chars(fname) &&
 | 
				
			||||||
	       !is_reserved_name(sbi, 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -276,7 +276,7 @@ struct ntfs_sb_info {
 | 
				
			||||||
		__le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY.
 | 
							__le16 flags; // Cached current VOLUME_INFO::flags, VOLUME_FLAG_DIRTY.
 | 
				
			||||||
		u8 major_ver;
 | 
							u8 major_ver;
 | 
				
			||||||
		u8 minor_ver;
 | 
							u8 minor_ver;
 | 
				
			||||||
		char label[65];
 | 
							char label[256];
 | 
				
			||||||
		bool real_dirty; // Real fs state.
 | 
							bool real_dirty; // Real fs state.
 | 
				
			||||||
	} volume;
 | 
						} volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,7 +286,6 @@ struct ntfs_sb_info {
 | 
				
			||||||
		struct ntfs_inode *ni;
 | 
							struct ntfs_inode *ni;
 | 
				
			||||||
		u32 next_id;
 | 
							u32 next_id;
 | 
				
			||||||
		u64 next_off;
 | 
							u64 next_off;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		__le32 def_security_id;
 | 
							__le32 def_security_id;
 | 
				
			||||||
	} security;
 | 
						} security;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -314,6 +313,7 @@ struct ntfs_sb_info {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ntfs_mount_options *options;
 | 
						struct ntfs_mount_options *options;
 | 
				
			||||||
	struct ratelimit_state msg_ratelimit;
 | 
						struct ratelimit_state msg_ratelimit;
 | 
				
			||||||
 | 
						struct proc_dir_entry *procdir;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* One MFT record(usually 1024 bytes), consists of attributes. */
 | 
					/* 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,
 | 
					int run_deallocate(struct ntfs_sb_info *sbi, const struct runs_tree *run,
 | 
				
			||||||
		   bool trim);
 | 
							   bool trim);
 | 
				
			||||||
bool valid_windows_name(struct ntfs_sb_info *sbi, const struct le_str *name);
 | 
					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 */
 | 
					/* Globals from index.c */
 | 
				
			||||||
int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit);
 | 
					int indx_used_bit(struct ntfs_index *indx, struct ntfs_inode *ni, size_t *bit);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										134
									
								
								fs/ntfs3/super.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								fs/ntfs3/super.c
									
									
									
									
									
								
							| 
						 | 
					@ -57,6 +57,7 @@
 | 
				
			||||||
#include <linux/minmax.h>
 | 
					#include <linux/minmax.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/nls.h>
 | 
					#include <linux/nls.h>
 | 
				
			||||||
 | 
					#include <linux/proc_fs.h>
 | 
				
			||||||
#include <linux/seq_file.h>
 | 
					#include <linux/seq_file.h>
 | 
				
			||||||
#include <linux/statfs.h>
 | 
					#include <linux/statfs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -441,6 +442,103 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
 | 
				
			||||||
	return 0;
 | 
						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 kmem_cache *ntfs_inode_cachep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct inode *ntfs_alloc_inode(struct super_block *sb)
 | 
					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;
 | 
						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. */
 | 
						/* Mark rw ntfs as clear, if possible. */
 | 
				
			||||||
	ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);
 | 
						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);
 | 
							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;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
put_inode_out:
 | 
					put_inode_out:
 | 
				
			||||||
| 
						 | 
					@ -1630,6 +1752,12 @@ static int __init init_ntfs_fs(void)
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
 | 
						if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
 | 
				
			||||||
		pr_info("ntfs3: Read-only LZX/Xpress compression included\n");
 | 
							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();
 | 
						err = ntfs3_init_bitmap();
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
| 
						 | 
					@ -1661,6 +1789,12 @@ static void __exit exit_ntfs_fs(void)
 | 
				
			||||||
	kmem_cache_destroy(ntfs_inode_cachep);
 | 
						kmem_cache_destroy(ntfs_inode_cachep);
 | 
				
			||||||
	unregister_filesystem(&ntfs_fs_type);
 | 
						unregister_filesystem(&ntfs_fs_type);
 | 
				
			||||||
	ntfs3_exit_bitmap();
 | 
						ntfs3_exit_bitmap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PROC_FS
 | 
				
			||||||
 | 
						if (proc_info_root)
 | 
				
			||||||
 | 
							remove_proc_entry("fs/ntfs3", NULL);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue