|
@@ -2272,6 +2272,8 @@ EXPORT_SYMBOL(vfs_path_lookup);
|
|
|
*
|
|
|
* Note that this routine is purely a helper for filesystem usage and should
|
|
|
* not be called by generic code.
|
|
|
+ *
|
|
|
+ * The caller must hold base->i_mutex.
|
|
|
*/
|
|
|
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
|
|
{
|
|
@@ -2315,6 +2317,75 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
|
|
}
|
|
|
EXPORT_SYMBOL(lookup_one_len);
|
|
|
|
|
|
+/**
|
|
|
+ * lookup_one_len_unlocked - filesystem helper to lookup single pathname component
|
|
|
+ * @name: pathname component to lookup
|
|
|
+ * @base: base directory to lookup from
|
|
|
+ * @len: maximum length @len should be interpreted to
|
|
|
+ *
|
|
|
+ * Note that this routine is purely a helper for filesystem usage and should
|
|
|
+ * not be called by generic code.
|
|
|
+ *
|
|
|
+ * Unlike lookup_one_len, it should be called without the parent
|
|
|
+ * i_mutex held, and will take the i_mutex itself if necessary.
|
|
|
+ */
|
|
|
+struct dentry *lookup_one_len_unlocked(const char *name,
|
|
|
+ struct dentry *base, int len)
|
|
|
+{
|
|
|
+ struct qstr this;
|
|
|
+ unsigned int c;
|
|
|
+ int err;
|
|
|
+ struct dentry *ret;
|
|
|
+
|
|
|
+ this.name = name;
|
|
|
+ this.len = len;
|
|
|
+ this.hash = full_name_hash(name, len);
|
|
|
+ if (!len)
|
|
|
+ return ERR_PTR(-EACCES);
|
|
|
+
|
|
|
+ if (unlikely(name[0] == '.')) {
|
|
|
+ if (len < 2 || (len == 2 && name[1] == '.'))
|
|
|
+ return ERR_PTR(-EACCES);
|
|
|
+ }
|
|
|
+
|
|
|
+ while (len--) {
|
|
|
+ c = *(const unsigned char *)name++;
|
|
|
+ if (c == '/' || c == '\0')
|
|
|
+ return ERR_PTR(-EACCES);
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * See if the low-level filesystem might want
|
|
|
+ * to use its own hash..
|
|
|
+ */
|
|
|
+ if (base->d_flags & DCACHE_OP_HASH) {
|
|
|
+ int err = base->d_op->d_hash(base, &this);
|
|
|
+ if (err < 0)
|
|
|
+ return ERR_PTR(err);
|
|
|
+ }
|
|
|
+
|
|
|
+ err = inode_permission(base->d_inode, MAY_EXEC);
|
|
|
+ if (err)
|
|
|
+ return ERR_PTR(err);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * __d_lookup() is used to try to get a quick answer and avoid the
|
|
|
+ * mutex. A false-negative does no harm.
|
|
|
+ */
|
|
|
+ ret = __d_lookup(base, &this);
|
|
|
+ if (ret && unlikely(ret->d_flags & DCACHE_OP_REVALIDATE)) {
|
|
|
+ dput(ret);
|
|
|
+ ret = NULL;
|
|
|
+ }
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ mutex_lock(&base->d_inode->i_mutex);
|
|
|
+ ret = __lookup_hash(&this, base, 0);
|
|
|
+ mutex_unlock(&base->d_inode->i_mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(lookup_one_len_unlocked);
|
|
|
+
|
|
|
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
|
|
|
struct path *path, int *empty)
|
|
|
{
|