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

2007-06-25 Thread Andrew Morton
On Mon, 25 Jun 2007 14:17:19 +0200 (CEST) Roman Zippel <[EMAIL PROTECTED]> 
wrote:

> +/*
> + * 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)
> +{
> + struct super_block *sb = dentry->d_sb;
> + const char *astr;
> + const u16 *dstr;
> + int casefold, decompose, size, dsize, len;
> + unsigned long hash;
> + wchar_t c;
> + u16 c2;
> +
> + casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
> + decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
> + hash = init_name_hash();
> + astr = str->name;
> + len = str->len;
> + while (len > 0) {
> + size = asc2unichar(sb, astr, len, );
> + astr += size;
> + len -= size;
> +
> + if (decompose && (dstr = decompose_unichar(c, ))) {
> + do {
> + c2 = *dstr++;
> + if (!casefold || (c2 = case_fold(c2)))
> + hash = partial_name_hash(c2, hash);
> + } while (--dsize > 0);

Are you really sure that we cannot start this loop with dsize==0?  This isn't
obviously true to these bleary eyes.

> + } else {
> + c2 = c;
> + if (!casefold || (c2 = case_fold(c2)))
> + hash = partial_name_hash(c2, hash);
> + }
> + }
> + str->hash = end_name_hash(hash);
-
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/


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

2007-06-25 Thread Roman Zippel
Hi,

On Wed, 20 Jun 2007, Duane Griffin wrote:

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

The changes in the previous patch required a few changes in this patch as 
well, but there were also a few small problems. The case condition wasn't 
quite correct and some characters have to be ignored during compare/hash.

bye, Roman


From: Duane Griffin <[EMAIL PROTECTED]>

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]>
Signed-off-by: Roman Zippel <[EMAIL PROTECTED]>

---
 fs/hfsplus/btree.c  |4 +
 fs/hfsplus/dir.c|2 
 fs/hfsplus/hfsplus_fs.h |4 +
 fs/hfsplus/inode.c  |5 +
 fs/hfsplus/super.c  |1 
 fs/hfsplus/unicode.c|  123 
 6 files changed, 138 insertions(+), 1 deletion(-)

Index: linux-2.6/fs/hfsplus/dir.c
===
--- linux-2.6.orig/fs/hfsplus/dir.c 2007-04-26 19:45:57.0 +0200
+++ linux-2.6/fs/hfsplus/dir.c  2007-06-25 13:39:46.0 +0200
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(str
u16 type;
 
sb = dir->i_sb;
+
+   dentry->d_op = _dentry_operations;
dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, );
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, >d_name);
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h  2007-04-26 19:45:57.0 
+0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h   2007-06-25 12:59:16.0 +0200
@@ -150,6 +150,7 @@ struct hfsplus_sb_info {
 #define HFSPLUS_SB_NODECOMPOSE 0x0002
 #define HFSPLUS_SB_FORCE   0x0004
 #define HFSPLUS_SB_HFSX0x0008
+#define HFSPLUS_SB_CASEFOLD0x0010
 
 
 struct hfsplus_inode_info {
@@ -321,6 +322,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 +355,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 *);
Index: linux-2.6/fs/hfsplus/inode.c
===
--- linux-2.6.orig/fs/hfsplus/inode.c   2007-04-26 19:45:57.0 +0200
+++ linux-2.6/fs/hfsplus/inode.c2007-06-25 13:52:54.0 +0200
@@ -130,6 +130,11 @@ const struct address_space_operations hf
.writepages = hfsplus_writepages,
 };
 
+struct dentry_operations hfsplus_dentry_operations = {
+   .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)
 {
Index: linux-2.6/fs/hfsplus/unicode.c
===
--- linux-2.6.orig/fs/hfsplus/unicode.c 2007-06-25 12:59:15.0 +0200
+++ linux-2.6/fs/hfsplus/unicode.c  2007-06-25 13:35:23.0 +0200
@@ -312,3 +312,126 @@ 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)
+{
+   struct super_block *sb = dentry->d_sb;
+   const char *astr;
+   const u16 *dstr;
+   int casefold, decompose, size, dsize, len;
+   unsigned long hash;
+   wchar_t c;
+   u16 c2;
+
+   casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+   decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+   hash 

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

2007-06-25 Thread Roman Zippel
Hi,

On Wed, 20 Jun 2007, Duane Griffin wrote:

 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.

The changes in the previous patch required a few changes in this patch as 
well, but there were also a few small problems. The case condition wasn't 
quite correct and some characters have to be ignored during compare/hash.

bye, Roman


From: Duane Griffin [EMAIL PROTECTED]

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]
Signed-off-by: Roman Zippel [EMAIL PROTECTED]

---
 fs/hfsplus/btree.c  |4 +
 fs/hfsplus/dir.c|2 
 fs/hfsplus/hfsplus_fs.h |4 +
 fs/hfsplus/inode.c  |5 +
 fs/hfsplus/super.c  |1 
 fs/hfsplus/unicode.c|  123 
 6 files changed, 138 insertions(+), 1 deletion(-)

Index: linux-2.6/fs/hfsplus/dir.c
===
--- linux-2.6.orig/fs/hfsplus/dir.c 2007-04-26 19:45:57.0 +0200
+++ linux-2.6/fs/hfsplus/dir.c  2007-06-25 13:39:46.0 +0200
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(str
u16 type;
 
sb = dir-i_sb;
+
+   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);
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h  2007-04-26 19:45:57.0 
+0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h   2007-06-25 12:59:16.0 +0200
@@ -150,6 +150,7 @@ struct hfsplus_sb_info {
 #define HFSPLUS_SB_NODECOMPOSE 0x0002
 #define HFSPLUS_SB_FORCE   0x0004
 #define HFSPLUS_SB_HFSX0x0008
+#define HFSPLUS_SB_CASEFOLD0x0010
 
 
 struct hfsplus_inode_info {
@@ -321,6 +322,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 +355,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 *);
Index: linux-2.6/fs/hfsplus/inode.c
===
--- linux-2.6.orig/fs/hfsplus/inode.c   2007-04-26 19:45:57.0 +0200
+++ linux-2.6/fs/hfsplus/inode.c2007-06-25 13:52:54.0 +0200
@@ -130,6 +130,11 @@ const struct address_space_operations hf
.writepages = hfsplus_writepages,
 };
 
+struct dentry_operations hfsplus_dentry_operations = {
+   .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)
 {
Index: linux-2.6/fs/hfsplus/unicode.c
===
--- linux-2.6.orig/fs/hfsplus/unicode.c 2007-06-25 12:59:15.0 +0200
+++ linux-2.6/fs/hfsplus/unicode.c  2007-06-25 13:35:23.0 +0200
@@ -312,3 +312,126 @@ 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)
+{
+   struct super_block *sb = dentry-d_sb;
+   const char *astr;
+   const u16 *dstr;
+   int casefold, decompose, size, dsize, len;
+   unsigned long hash;
+   wchar_t c;
+   u16 c2;
+
+   casefold = (HFSPLUS_SB(sb).flags  HFSPLUS_SB_CASEFOLD);
+   decompose = !(HFSPLUS_SB(sb).flags  HFSPLUS_SB_NODECOMPOSE);
+   hash = 

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

2007-06-25 Thread Andrew Morton
On Mon, 25 Jun 2007 14:17:19 +0200 (CEST) Roman Zippel [EMAIL PROTECTED] 
wrote:

 +/*
 + * 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)
 +{
 + struct super_block *sb = dentry-d_sb;
 + const char *astr;
 + const u16 *dstr;
 + int casefold, decompose, size, dsize, len;
 + unsigned long hash;
 + wchar_t c;
 + u16 c2;
 +
 + casefold = (HFSPLUS_SB(sb).flags  HFSPLUS_SB_CASEFOLD);
 + decompose = !(HFSPLUS_SB(sb).flags  HFSPLUS_SB_NODECOMPOSE);
 + hash = init_name_hash();
 + astr = str-name;
 + len = str-len;
 + while (len  0) {
 + size = asc2unichar(sb, astr, len, c);
 + astr += size;
 + len -= size;
 +
 + if (decompose  (dstr = decompose_unichar(c, dsize))) {
 + do {
 + c2 = *dstr++;
 + if (!casefold || (c2 = case_fold(c2)))
 + hash = partial_name_hash(c2, hash);
 + } while (--dsize  0);

Are you really sure that we cannot start this loop with dsize==0?  This isn't
obviously true to these bleary eyes.

 + } else {
 + c2 = c;
 + if (!casefold || (c2 = case_fold(c2)))
 + hash = partial_name_hash(c2, hash);
 + }
 + }
 + str-hash = end_name_hash(hash);
-
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/


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

2007-06-19 Thread Duane Griffin
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 = _dentry_operations;
+
dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, );
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, >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();
 
+   if (!(HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) ||
+   !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE))
+   sb->s_root->d_op = _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, );
+   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;

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

2007-06-19 Thread Duane Griffin
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;