ANDROID: sdcardfs: Allow non-owners to touch
[firefly-linux-kernel-4.4.55.git] / fs / sdcardfs / dentry.c
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  */
29 static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags)
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
38         if (flags & LOOKUP_RCU)
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);
79                 spin_lock(&lower_dentry->d_lock);
80         } else {
81                 spin_lock(&lower_dentry->d_lock);
82                 spin_lock(&dentry->d_lock);
83         }
84
85         if (dentry->d_name.len != lower_dentry->d_name.len) {
86                 __d_drop(dentry);
87                 err = 0;
88         } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name,
89                                 dentry->d_name.len) != 0) {
90                 __d_drop(dentry);
91                 err = 0;
92         }
93
94         if (dentry < lower_dentry) {
95                 spin_unlock(&lower_dentry->d_lock);
96                 spin_unlock(&dentry->d_lock);
97         } else {
98                 spin_unlock(&dentry->d_lock);
99                 spin_unlock(&lower_dentry->d_lock);
100         }
101
102 out:
103         dput(parent_dentry);
104         dput(lower_cur_parent_dentry);
105         sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
106         sdcardfs_put_real_lower(dentry, &lower_path);
107         return err;
108 }
109
110 static void sdcardfs_d_release(struct dentry *dentry)
111 {
112         /* release and reset the lower paths */
113         if(has_graft_path(dentry)) {
114                 sdcardfs_put_reset_orig_path(dentry);
115         }
116         sdcardfs_put_reset_lower_path(dentry);
117         free_dentry_private_data(dentry);
118         return;
119 }
120
121 static int sdcardfs_hash_ci(const struct dentry *dentry,
122                                 struct qstr *qstr)
123 {
124         /*
125          * This function is copy of vfat_hashi.
126          * FIXME Should we support national language?
127          *       Refer to vfat_hashi()
128          * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
129          */
130         const unsigned char *name;
131         unsigned int len;
132         unsigned long hash;
133
134         name = qstr->name;
135         //len = vfat_striptail_len(qstr);
136         len = qstr->len;
137
138         hash = init_name_hash();
139         while (len--)
140                 //hash = partial_name_hash(nls_tolower(t, *name++), hash);
141                 hash = partial_name_hash(tolower(*name++), hash);
142         qstr->hash = end_name_hash(hash);
143
144         return 0;
145 }
146
147 /*
148  * Case insensitive compare of two vfat names.
149  */
150 static int sdcardfs_cmp_ci(const struct dentry *parent,
151                 const struct dentry *dentry,
152                 unsigned int len, const char *str, const struct qstr *name)
153 {
154         /* This function is copy of vfat_cmpi */
155         // FIXME Should we support national language?
156         //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
157         //unsigned int alen, blen;
158
159         /* A filename cannot end in '.' or we treat it like it has none */
160         /*
161         alen = vfat_striptail_len(name);
162         blen = __vfat_striptail_len(len, str);
163         if (alen == blen) {
164                 if (nls_strnicmp(t, name->name, str, alen) == 0)
165                         return 0;
166         }
167         */
168         if (name->len == len) {
169                 if (strncasecmp(name->name, str, len) == 0)
170                         return 0;
171         }
172         return 1;
173 }
174
175 static void sdcardfs_canonical_path(const struct path *path, struct path *actual_path) {
176         sdcardfs_get_real_lower(path->dentry, actual_path);
177 }
178
179 const struct dentry_operations sdcardfs_ci_dops = {
180         .d_revalidate   = sdcardfs_d_revalidate,
181         .d_release      = sdcardfs_d_release,
182         .d_hash         = sdcardfs_hash_ci,
183         .d_compare      = sdcardfs_cmp_ci,
184         .d_canonical_path = sdcardfs_canonical_path,
185 };
186