[patch 2/2] HFS+: Add custom dentry hash and comparison operations

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

 



Add custom dentry hash and comparison operations for HFS+ filesystems
that are case-insensitive and/or do automatic unicode decomposition.
The new operations reuse the existing HFS+ ASCII to unicode conversion,
unicode decomposition and case folding functionality.

Signed-off-by: Duane Griffin <[email protected]>
---

--- linux-2.6.21.orig/fs/hfsplus/dir.c
+++ linux-2.6.21/fs/hfsplus/dir.c
@@ -36,6 +36,11 @@ static struct dentry *hfsplus_lookup(str
 	u16 type;
 
 	sb = dir->i_sb;
+
+	if (!(HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) ||
+	    !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE))
+		dentry->d_op = &hfsplus_dentry_operations;
+
 	dentry->d_fsdata = NULL;
 	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
 	hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
--- linux-2.6.21.orig/fs/hfsplus/hfsplus_fs.h
+++ linux-2.6.21/fs/hfsplus/hfsplus_fs.h
@@ -321,6 +321,7 @@ void hfsplus_file_truncate(struct inode 
 /* inode.c */
 extern const struct address_space_operations hfsplus_aops;
 extern const struct address_space_operations hfsplus_btree_aops;
+extern struct dentry_operations hfsplus_dentry_operations;
 
 void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *);
 void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *);
@@ -353,6 +354,8 @@ int hfsplus_strcasecmp(const struct hfsp
 int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
 int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
 int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str);
+int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2);
 
 /* wrapper.c */
 int hfsplus_read_wrapper(struct super_block *);
--- linux-2.6.21.orig/fs/hfsplus/inode.c
+++ linux-2.6.21/fs/hfsplus/inode.c
@@ -130,6 +130,12 @@ const struct address_space_operations hf
 	.writepages	= hfsplus_writepages,
 };
 
+struct dentry_operations hfsplus_dentry_operations = {
+	.d_revalidate = NULL,
+	.d_hash       = hfsplus_hash_dentry,
+	.d_compare    = hfsplus_compare_dentry,
+};
+
 static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
 					  struct nameidata *nd)
 {
--- linux-2.6.21.orig/fs/hfsplus/super.c
+++ linux-2.6.21/fs/hfsplus/super.c
@@ -396,6 +396,10 @@ static int hfsplus_fill_super(struct sup
 	} else
 		hfs_find_exit(&fd);
 
+	if (!(HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) ||
+	    !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE))
+		sb->s_root->d_op = &hfsplus_dentry_operations;
+
 	if (sb->s_flags & MS_RDONLY)
 		goto out;
 
--- linux-2.6.21.orig/fs/hfsplus/unicode.c
+++ linux-2.6.21/fs/hfsplus/unicode.c
@@ -314,6 +314,22 @@ static int asc2ucd(struct super_block *s
 	return size;
 }
 
+/*
+ * Convert a ASCII character(s) to a unicode character.
+ * The unicode character will be decomposed and/or case-folded, if required.
+ * Returns the number of ASCII characters converted.
+ */
+static int asc2ucdf(struct super_block *sb,
+	const char *astr, int len, struct decomposed_uc *duc)
+{
+	int ii;
+	int size = asc2ucd(sb, astr, len, duc);
+	bool fold = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX);
+	for (ii = 0; fold && ii <= duc->size; ++ii)
+		duc->str[ii] = case_fold(duc->str[ii]);
+	return size;
+}
+
 int hfsplus_asc2uni(struct super_block *sb,
 	struct hfsplus_unistr *ustr, const char *astr, int len)
 {
@@ -336,3 +352,89 @@ int hfsplus_asc2uni(struct super_block *
 		return -ENAMETOOLONG;
 	return 0;
 }
+
+/*
+ * Hash a string to an integer as appropriate for the HFS+ filesystem.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
+{
+	int len = str->len;
+	const char *astr = str->name;
+	struct decomposed_uc duc;
+	unsigned hash = init_name_hash();
+
+	while (len > 0) {
+		int ii;
+		int size = asc2ucdf(dentry->d_sb, astr, len, &duc);
+		astr += size;
+		len -= size;
+		for (ii = 0; ii < duc.size; ++ii) {
+			if (duc.str[ii])
+				hash = partial_name_hash(duc.str[ii], hash);
+		}
+	}
+	str->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+/*
+ * Compare strings with HFS+ filename ordering.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int
+hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2)
+{
+	int off1 = 0;
+	int off2 = 0;
+	struct decomposed_uc duc1;
+	struct decomposed_uc duc2;
+	int len1 = s1->len;
+	int len2 = s2->len;
+	const char *astr1 = s1->name;
+	const char *astr2 = s2->name;
+
+	duc1.size = 0;
+	duc2.size = 0;
+
+	while ((off1 < duc1.size || len1 > 0) &&
+	       (off2 < duc2.size || len2 > 0)) {
+
+		if (off1 == duc1.size) {
+			int size = asc2ucdf(dentry->d_sb, astr1, len1, &duc1);
+			astr1 += size;
+			len1 -= size;
+			off1 = 0;
+		}
+
+		if (off2 == duc2.size) {
+			int size = asc2ucdf(dentry->d_sb, astr2, len2, &duc2);
+			astr2 += size;
+			len2 -= size;
+			off2 = 0;
+		}
+
+		while (off1 < duc1.size && !duc1.str[off1])
+			++off1;
+		while (off2 < duc2.size && !duc2.str[off2])
+			++off2;
+
+		while (off1 < duc1.size && off2 < duc2.size) {
+			if (duc1.str[off1] < duc2.str[off2])
+				return -1;
+			if (duc1.str[off1] > duc2.str[off2])
+				return 1;
+			++off1;
+			++off2;
+		}
+	}
+
+	if (len1 < len2)
+		return -1;
+	if (len1 > len2)
+		return 1;
+	return 0;
+}

-- 
"I never could learn to drink that blood and call it wine" - Bob Dylan
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux