Samsung SCH-I545 (Verizon) source updates
/fs/sdcardfs/lookup.c
blob:2c93cba2ed73abddb834078ddc97c52034249714 -> blob:59d82a78b44507827e76bc4f1112840a9cbce7ba
--- fs/sdcardfs/lookup.c
+++ fs/sdcardfs/lookup.c
@@ -193,6 +193,134 @@ out:
return err;
}
+#ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT
+struct sdcardfs_dirent {
+ unsigned long d_ino;
+ unsigned long d_off;
+ unsigned short d_type;
+ char d_name[SDCARDFS_DIRENT_SIZE];
+};
+
+struct sdcardfs_getdents_callback {
+ struct sdcardfs_dirent * dirent;
+ int result;
+};
+
+static int sdcardfs_fillonedir(void * __buf, const char * name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
+{
+ /* This function is copy of fillonedir */
+ struct sdcardfs_dirent * dirent;
+ struct sdcardfs_getdents_callback * buf;
+ unsigned long d_ino;
+
+ buf = (struct sdcardfs_getdents_callback *) __buf;
+
+ if (buf->result)
+ return -EINVAL;
+ d_ino = ino;
+
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
+ buf->result = -EOVERFLOW;
+ return -EOVERFLOW;
+ }
+
+ buf->result++;
+ dirent = buf->dirent;
+
+ dirent->d_ino = d_ino;
+ dirent->d_off = offset;
+ dirent->d_type = d_type;
+ memcpy(dirent->d_name, name, namlen);
+ dirent->d_name[namlen] = 0;
+
+ return 0;
+}
+
+static int sdcardfs_getdents(struct file * file, struct sdcardfs_dirent * dirent)
+{
+ /* This function is copy old_readdir */
+ int error;
+ struct sdcardfs_getdents_callback buf;
+
+ error = -EBADF;
+
+ if (!file)
+ goto out;
+
+ buf.result = 0;
+ buf.dirent = dirent;
+
+ error = vfs_readdir(file, sdcardfs_fillonedir, &buf);
+ if (buf.result)
+ error = buf.result;
+out:
+ return error;
+}
+
+/*
+ * look for case-insensitive matching entry name.
+ * Returns :
+ * - char * of matching entry if found.
+ * - NULL if no matching entry
+ * - ERR_PTR on error
+ *
+ */
+static void * find_case_insensitive(struct path * lower_parent_path, const char * name)
+{
+ void * ret = NULL;
+ struct file *lower_dirp = NULL;
+ struct sdcardfs_dirent dirent;
+
+ int err;
+
+ /*
+ * At the end of this function, filp_close or dentry_open (if fails)
+ * will decrease refernce count of lower_parent_path.
+ * (ie, path->dentry->d_count and path->mnt->mnt_count)
+ * To prevent those counter from dropping to zero,
+ * we increase the counters in advance.
+ */
+ path_get(lower_parent_path);
+
+ lower_dirp = dentry_open(lower_parent_path->dentry,
+ lower_parent_path->mnt, O_RDONLY, current_cred());
+ if (IS_ERR(lower_dirp)) {
+ return (void *)lower_dirp;
+ }
+
+ while (1) {
+ err = sdcardfs_getdents(lower_dirp, &dirent);
+ if (likely(err > 0)) {
+ /* we got a direntry */
+ if (unlikely(!strcasecmp(dirent.d_name, name))) {
+ int len;
+ len = strlen(dirent.d_name) + 1;
+ ret = kmalloc(len, GFP_KERNEL);
+ if (ret == NULL)
+ ret = ERR_PTR(-ENOMEM);
+ else
+ strcpy(ret, dirent.d_name);
+ break;
+ }
+ } else if (err == 0) {
+ /* end of directory */
+ ret = NULL;
+ break;
+ } else {
+ /* err < 0 : error */
+ ret = ERR_PTR(err);
+ break;
+ }
+ }
+
+ filp_close(lower_dirp, NULL);
+
+ return ret;
+}
+
+#endif
+
/*
* Main driver function for sdcardfs's lookup.
*
@@ -223,16 +351,14 @@ static struct dentry *__sdcardfs_lookup(
lower_dir_mnt = lower_parent_path->mnt;
/* Use vfs_path_lookup to check if the dentry exists or not */
-#ifdef CONFIG_SDCARD_FS_CI_SEARCH
- err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name,
- LOOKUP_CASE_INSENSITIVE, &lower_path);
-#else
err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
&lower_path);
-#endif
/* no error: handle positive dentries */
if (!err) {
+#ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT
+dentry_found:
+#endif
sdcardfs_set_lower_path(dentry, &lower_path);
err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path);
if (err) /* path_put underlying path on error */
@@ -240,6 +366,26 @@ static struct dentry *__sdcardfs_lookup(
goto out;
}
+#ifdef SDCARDFS_CASE_INSENSITIVE_MATCH_SUPPORT
+ if (err == -ENOENT) {
+ /* try case insensetive match */
+ char * match_name = NULL;
+
+ match_name = find_case_insensitive(lower_parent_path, name);
+ if (unlikely(IS_ERR(match_name))) {
+ err = PTR_ERR(match_name);
+ } else if (match_name) {
+ /* found */
+ err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt,
+ match_name, 0, &lower_path);
+ kfree(match_name);
+ if (!err)
+ goto dentry_found;
+ }
+ /* no match */
+ }
+#endif
+
/*
* We don't consider ENOENT an error, and we want to return a
* negative dentry.