ANDROID: sdcardfs: Fix case insensitive lookup
authorDaniel Rosenberg <drosen@google.com>
Thu, 2 Mar 2017 01:04:41 +0000 (17:04 -0800)
committerStricted <info@stricted.net>
Thu, 11 Oct 2018 16:03:26 +0000 (18:03 +0200)
The previous case insensitive lookup relied on the
entry being present in the dcache. This instead uses
iterate_dir to find the correct case.

Signed-off-by: Daniel Rosenberg <drosen@google.com
bug: 35633782
Change-Id: I556f7090773468c1943c89a5e2aa07f746ba49c5

fs/sdcardfs/lookup.c

index 87b47e34d80d4aea662bafc5918f63dd2daa8fcd..e1930d66882ed9708540883caca1fb10934aef17 100644 (file)
@@ -206,6 +206,28 @@ out:
        return err;
 }
 
+struct sdcardfs_name_data {
+       struct dir_context ctx;
+       const struct qstr *to_find;
+       char *name;
+       bool found;
+};
+
+static int sdcardfs_name_match(void *__buf, const char *name, int namelen,
+               loff_t offset, u64 ino, unsigned int d_type)
+{
+       struct sdcardfs_name_data *buf = (struct sdcardfs_name_data *) __buf;
+       struct qstr candidate = QSTR_INIT(name, namelen);
+
+       if (qstr_case_eq(buf->to_find, &candidate)) {
+               memcpy(buf->name, name, namelen);
+               buf->name[namelen] = 0;
+               buf->found = true;
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * Main driver function for sdcardfs's lookup.
  *
@@ -242,27 +264,39 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
                                &lower_path);
        /* check for other cases */
        if (err == -ENOENT) {
-               struct dentry *child;
-               struct dentry *match = NULL;
-               mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
-               spin_lock(&lower_dir_dentry->d_lock);
-               list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_u.d_child) {
-                       if (child && child->d_inode) {
-                               if (qstr_case_eq(&child->d_name, name)) {
-                                       match = dget(child);
-                                       break;
-                               }
-                       }
+               struct file *file;
+               const struct cred *cred = current_cred();
+
+               struct sdcardfs_name_data buffer = {
+                       .ctx.actor = sdcardfs_name_match,
+                       .to_find = name,
+                       .name = __getname(),
+                       .found = false,
+               };
+
+               if (!buffer.name) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               file = dentry_open(lower_parent_path, O_RDONLY, cred);
+               if (IS_ERR(file)) {
+                       err = PTR_ERR(file);
+                       goto put_name;
                }
-               spin_unlock(&lower_dir_dentry->d_lock);
-               mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
-               if (match) {
+               err = iterate_dir(file, &buffer.ctx);
+               fput(file);
+               if (err)
+                       goto put_name;
+
+               if (buffer.found)
                        err = vfs_path_lookup(lower_dir_dentry,
                                                lower_dir_mnt,
-                                               match->d_name.name, 0,
+                                               buffer.name, 0,
                                                &lower_path);
-                       dput(match);
-               }
+               else
+                       err = -ENOENT;
+put_name:
+               __putname(buffer.name);
        }
 
        /* no error: handle positive dentries */