Commit | Line | Data |
---|---|---|
ee184c81 DC |
1 | /* |
2 | * fs/sdcardfs/dentry.c | |
3 | * | |
4 | * Copyright (c) 2013 Samsung Electronics Co. Ltd | |
5 | * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun, | |
6 | * Sunghwan Yun, Sungjong Seo | |
7 | * | |
8 | * This program has been developed as a stackable file system based on | |
9 | * the WrapFS which written by | |
10 | * | |
11 | * Copyright (c) 1998-2011 Erez Zadok | |
12 | * Copyright (c) 2009 Shrikar Archak | |
13 | * Copyright (c) 2003-2011 Stony Brook University | |
14 | * Copyright (c) 2003-2011 The Research Foundation of SUNY | |
15 | * | |
16 | * This file is dual licensed. It may be redistributed and/or modified | |
17 | * under the terms of the Apache 2.0 License OR version 2 of the GNU | |
18 | * General Public License. | |
19 | */ | |
20 | ||
21 | #include "sdcardfs.h" | |
22 | #include "linux/ctype.h" | |
23 | ||
24 | /* | |
25 | * returns: -ERRNO if error (returned to user) | |
26 | * 0: tell VFS to invalidate dentry | |
27 | * 1: dentry is valid | |
28 | */ | |
542a676e | 29 | static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) |
ee184c81 DC |
30 | { |
31 | int err = 1; | |
32 | struct path parent_lower_path, lower_path; | |
33 | struct dentry *parent_dentry = NULL; | |
34 | struct dentry *parent_lower_dentry = NULL; | |
35 | struct dentry *lower_cur_parent_dentry = NULL; | |
36 | struct dentry *lower_dentry = NULL; | |
37 | ||
542a676e | 38 | if (flags & LOOKUP_RCU) |
ee184c81 DC |
39 | return -ECHILD; |
40 | ||
41 | spin_lock(&dentry->d_lock); | |
42 | if (IS_ROOT(dentry)) { | |
43 | spin_unlock(&dentry->d_lock); | |
44 | return 1; | |
45 | } | |
46 | spin_unlock(&dentry->d_lock); | |
47 | ||
48 | /* check uninitialized obb_dentry and | |
49 | * whether the base obbpath has been changed or not */ | |
50 | if (is_obbpath_invalid(dentry)) { | |
51 | d_drop(dentry); | |
52 | return 0; | |
53 | } | |
54 | ||
55 | parent_dentry = dget_parent(dentry); | |
56 | sdcardfs_get_lower_path(parent_dentry, &parent_lower_path); | |
57 | sdcardfs_get_real_lower(dentry, &lower_path); | |
58 | parent_lower_dentry = parent_lower_path.dentry; | |
59 | lower_dentry = lower_path.dentry; | |
60 | lower_cur_parent_dentry = dget_parent(lower_dentry); | |
61 | ||
62 | spin_lock(&lower_dentry->d_lock); | |
63 | if (d_unhashed(lower_dentry)) { | |
64 | spin_unlock(&lower_dentry->d_lock); | |
65 | d_drop(dentry); | |
66 | err = 0; | |
67 | goto out; | |
68 | } | |
69 | spin_unlock(&lower_dentry->d_lock); | |
70 | ||
71 | if (parent_lower_dentry != lower_cur_parent_dentry) { | |
72 | d_drop(dentry); | |
73 | err = 0; | |
74 | goto out; | |
75 | } | |
76 | ||
77 | if (dentry < lower_dentry) { | |
78 | spin_lock(&dentry->d_lock); | |
ea97094b | 79 | spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED); |
ee184c81 DC |
80 | } else { |
81 | spin_lock(&lower_dentry->d_lock); | |
ea97094b | 82 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
ee184c81 DC |
83 | } |
84 | ||
16e0ee27 | 85 | if (!qstr_case_eq(&dentry->d_name, &lower_dentry->d_name)) { |
ee184c81 DC |
86 | __d_drop(dentry); |
87 | err = 0; | |
88 | } | |
89 | ||
90 | if (dentry < lower_dentry) { | |
91 | spin_unlock(&lower_dentry->d_lock); | |
92 | spin_unlock(&dentry->d_lock); | |
93 | } else { | |
94 | spin_unlock(&dentry->d_lock); | |
95 | spin_unlock(&lower_dentry->d_lock); | |
96 | } | |
97 | ||
98 | out: | |
99 | dput(parent_dentry); | |
100 | dput(lower_cur_parent_dentry); | |
101 | sdcardfs_put_lower_path(parent_dentry, &parent_lower_path); | |
102 | sdcardfs_put_real_lower(dentry, &lower_path); | |
103 | return err; | |
104 | } | |
105 | ||
106 | static void sdcardfs_d_release(struct dentry *dentry) | |
107 | { | |
108 | /* release and reset the lower paths */ | |
109 | if(has_graft_path(dentry)) { | |
110 | sdcardfs_put_reset_orig_path(dentry); | |
111 | } | |
112 | sdcardfs_put_reset_lower_path(dentry); | |
113 | free_dentry_private_data(dentry); | |
114 | return; | |
115 | } | |
116 | ||
117 | static int sdcardfs_hash_ci(const struct dentry *dentry, | |
118 | const struct inode *inode, struct qstr *qstr) | |
119 | { | |
120 | /* | |
121 | * This function is copy of vfat_hashi. | |
122 | * FIXME Should we support national language? | |
123 | * Refer to vfat_hashi() | |
124 | * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; | |
125 | */ | |
126 | const unsigned char *name; | |
127 | unsigned int len; | |
128 | unsigned long hash; | |
129 | ||
130 | name = qstr->name; | |
131 | //len = vfat_striptail_len(qstr); | |
132 | len = qstr->len; | |
133 | ||
134 | hash = init_name_hash(); | |
135 | while (len--) | |
136 | //hash = partial_name_hash(nls_tolower(t, *name++), hash); | |
137 | hash = partial_name_hash(tolower(*name++), hash); | |
138 | qstr->hash = end_name_hash(hash); | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | /* | |
144 | * Case insensitive compare of two vfat names. | |
145 | */ | |
146 | static int sdcardfs_cmp_ci(const struct dentry *parent, | |
147 | const struct inode *pinode, | |
148 | const struct dentry *dentry, const struct inode *inode, | |
149 | unsigned int len, const char *str, const struct qstr *name) | |
150 | { | |
151 | /* This function is copy of vfat_cmpi */ | |
152 | // FIXME Should we support national language? | |
153 | //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; | |
154 | //unsigned int alen, blen; | |
155 | ||
156 | /* A filename cannot end in '.' or we treat it like it has none */ | |
157 | /* | |
158 | alen = vfat_striptail_len(name); | |
159 | blen = __vfat_striptail_len(len, str); | |
160 | if (alen == blen) { | |
161 | if (nls_strnicmp(t, name->name, str, alen) == 0) | |
162 | return 0; | |
163 | } | |
164 | */ | |
165 | if (name->len == len) { | |
16e0ee27 | 166 | if (str_n_case_eq(name->name, str, len)) |
ee184c81 DC |
167 | return 0; |
168 | } | |
169 | return 1; | |
170 | } | |
171 | ||
3e336725 DR |
172 | static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) { |
173 | sdcardfs_get_real_lower(path->dentry, actual_path); | |
174 | } | |
175 | ||
ee184c81 DC |
176 | const struct dentry_operations sdcardfs_ci_dops = { |
177 | .d_revalidate = sdcardfs_d_revalidate, | |
178 | .d_release = sdcardfs_d_release, | |
179 | .d_hash = sdcardfs_hash_ci, | |
180 | .d_compare = sdcardfs_cmp_ci, | |
3e336725 | 181 | .d_canonical_path = sdcardfs_canonical_path, |
ee184c81 DC |
182 | }; |
183 |