Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d45bce8faf55511ec7d7ffc301461d864d67f1af
Commit:     d45bce8faf55511ec7d7ffc301461d864d67f1af
Parent:     1e96b7ca1e8f17c5117da369daaa7cf2edfdf9b1
Author:     Duane Griffin <[EMAIL PROTECTED]>
AuthorDate: Sun Jul 15 23:41:23 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Mon Jul 16 09:05:49 2007 -0700

    HFS+: add custom dentry hash and comparison operations
    
    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]>
    
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[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 deletions(-)

diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 90ebab7..050d29c 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -62,8 +62,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 
id)
                if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) &&
                    (head->key_type == HFSPLUS_KEY_BINARY))
                        tree->keycmp = hfsplus_cat_bin_cmp_key;
-               else
+               else {
                        tree->keycmp = hfsplus_cat_case_cmp_key;
+                       HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD;
+               }
        } else {
                printk(KERN_ERR "hfs: unknown B*Tree requested\n");
                goto fail_page;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 80b5682..1955ee6 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, 
struct dentry *dentry,
        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);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 3915635..d9f5eda 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -150,6 +150,7 @@ struct hfsplus_sb_info {
 #define HFSPLUS_SB_NODECOMPOSE 0x0002
 #define HFSPLUS_SB_FORCE       0x0004
 #define HFSPLUS_SB_HFSX                0x0008
+#define HFSPLUS_SB_CASEFOLD    0x0010
 
 
 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 hfsplus_unistr *, const 
struct hfsplus_unist
 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 *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 409ce54..6f7c662 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -131,6 +131,11 @@ const struct address_space_operations hfsplus_aops = {
        .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)
 {
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 42570c9..6d87a2a 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -380,6 +380,7 @@ static int hfsplus_fill_super(struct super_block *sb, void 
*data, int silent)
                iput(root);
                goto cleanup;
        }
+       sb->s_root->d_op = &hfsplus_dentry_operations;
 
        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
        str.name = HFSP_HIDDENDIR_NAME;
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index 5df0052..9e10f94 100644
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -314,3 +314,126 @@ int hfsplus_asc2uni(struct super_block *sb, struct 
hfsplus_unistr *ustr,
                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 = 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);
+               } else {
+                       c2 = c;
+                       if (!casefold || (c2 = case_fold(c2)))
+                               hash = partial_name_hash(c2, 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)
+{
+       struct super_block *sb = dentry->d_sb;
+       int casefold, decompose, size;
+       int dsize1, dsize2, len1, len2;
+       const u16 *dstr1, *dstr2;
+       const char *astr1, *astr2;
+       u16 c1, c2;
+       wchar_t c;
+
+       casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+       decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+       astr1 = s1->name;
+       len1 = s1->len;
+       astr2 = s2->name;
+       len2 = s2->len;
+       dsize1 = dsize2 = 0;
+       dstr1 = dstr2 = NULL;
+
+       while (len1 > 0 && len2 > 0) {
+               if (!dsize1) {
+                       size = asc2unichar(sb, astr1, len1, &c);
+                       astr1 += size;
+                       len1 -= size;
+
+                       if (!decompose || !(dstr1 = decompose_unichar(c, 
&dsize1))) {
+                               c1 = c;
+                               dstr1 = &c1;
+                               dsize1 = 1;
+                       }
+               }
+
+               if (!dsize2) {
+                       size = asc2unichar(sb, astr2, len2, &c);
+                       astr2 += size;
+                       len2 -= size;
+
+                       if (!decompose || !(dstr2 = decompose_unichar(c, 
&dsize2))) {
+                               c2 = c;
+                               dstr2 = &c2;
+                               dsize2 = 1;
+                       }
+               }
+
+               c1 = *dstr1;
+               c2 = *dstr2;
+               if (casefold) {
+                       if  (!(c1 = case_fold(c1))) {
+                               dstr1++;
+                               dsize1--;
+                               continue;
+                       }
+                       if (!(c2 = case_fold(c2))) {
+                               dstr2++;
+                               dsize2--;
+                               continue;
+                       }
+               }
+               if (c1 < c2)
+                       return -1;
+               else if (c1 > c2)
+                       return 1;
+
+               dstr1++;
+               dsize1--;
+               dstr2++;
+               dsize2--;
+       }
+
+       if (len1 < len2)
+               return -1;
+       if (len1 > len2)
+               return 1;
+       return 0;
+}
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to