Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f5733b8 authored by Daniel Rosenberg's avatar Daniel Rosenberg
Browse files

ANDROID: sdcardfs: Fix case insensitive lookup



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: default avatarDaniel Rosenberg <drosen@google.com>
bug: 35633782
Change-Id: I556f7090773468c1943c89a5e2aa07f746ba49c5
parent abb2b2b9
Loading
Loading
Loading
Loading
+51 −17
Original line number Diff line number Diff line
@@ -206,6 +206,28 @@ int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
	return err;
}

struct sdcardfs_name_data {
	struct dir_context ctx;
	const struct qstr *to_find;
	char *name;
	bool found;
};

static int sdcardfs_name_match(struct dir_context *ctx, const char *name, int namelen,
		loff_t offset, u64 ino, unsigned int d_type)
{
	struct sdcardfs_name_data *buf = container_of(ctx, struct sdcardfs_name_data, ctx);
	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;
		inode_lock(d_inode(lower_dir_dentry));
		spin_lock(&lower_dir_dentry->d_lock);
		list_for_each_entry(child, &lower_dir_dentry->d_subdirs, d_child) {
			if (child && d_inode(child)) {
				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);
		inode_unlock(d_inode(lower_dir_dentry));
		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 */