cifsd: re-implement ksmbd_vfs_kern_path
re-implement ksmbd_vfs_kern_path() to change recursion to iteration. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
7c3d3e99ca
commit
3c20378325
103
fs/cifsd/vfs.c
103
fs/cifsd/vfs.c
@ -50,14 +50,6 @@ static char *extract_last_component(char *path)
|
||||
return p;
|
||||
}
|
||||
|
||||
static void rollback_path_modification(char *filename)
|
||||
{
|
||||
if (filename) {
|
||||
filename--;
|
||||
*filename = '/';
|
||||
}
|
||||
}
|
||||
|
||||
static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work,
|
||||
struct inode *parent_inode, struct inode *inode)
|
||||
{
|
||||
@ -1231,44 +1223,32 @@ static int __caseless_lookup(struct dir_context *ctx, const char *name,
|
||||
|
||||
/**
|
||||
* ksmbd_vfs_lookup_in_dir() - lookup a file in a directory
|
||||
* @dirname: directory name
|
||||
* @filename: filename to lookup
|
||||
* @dir: path info
|
||||
* @name: filename to lookup
|
||||
* @namelen: filename length
|
||||
*
|
||||
* Return: 0 on success, otherwise error
|
||||
*/
|
||||
static int ksmbd_vfs_lookup_in_dir(char *dirname, char *filename)
|
||||
static int ksmbd_vfs_lookup_in_dir(struct path *dir, char *name, size_t namelen)
|
||||
{
|
||||
struct path dir_path;
|
||||
int ret;
|
||||
struct file *dfilp;
|
||||
int flags = O_RDONLY | O_LARGEFILE;
|
||||
int dirnamelen = strlen(dirname);
|
||||
struct ksmbd_readdir_data readdir_data = {
|
||||
.ctx.actor = __caseless_lookup,
|
||||
.private = filename,
|
||||
.used = strlen(filename),
|
||||
.private = name,
|
||||
.used = namelen,
|
||||
.dirent_count = 0,
|
||||
};
|
||||
|
||||
ret = ksmbd_vfs_kern_path(dirname, 0, &dir_path, true);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
dfilp = dentry_open(&dir_path, flags, current_cred());
|
||||
if (IS_ERR(dfilp)) {
|
||||
path_put(&dir_path);
|
||||
ksmbd_err("cannot open directory %s\n", dirname);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfilp = dentry_open(dir, flags, current_cred());
|
||||
if (IS_ERR(dfilp))
|
||||
return PTR_ERR(dfilp);
|
||||
|
||||
ret = ksmbd_vfs_readdir(dfilp, &readdir_data);
|
||||
if (readdir_data.dirent_count > 0)
|
||||
ret = 0;
|
||||
|
||||
fput(dfilp);
|
||||
path_put(&dir_path);
|
||||
error:
|
||||
dirname[dirnamelen] = '/';
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1284,30 +1264,69 @@ error:
|
||||
int ksmbd_vfs_kern_path(char *name, unsigned int flags, struct path *path,
|
||||
bool caseless)
|
||||
{
|
||||
char *filename = NULL;
|
||||
int err;
|
||||
|
||||
if (name[0] != '/')
|
||||
return -EINVAL;
|
||||
|
||||
err = kern_path(name, flags, path);
|
||||
if (!err)
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
if (caseless) {
|
||||
filename = extract_last_component(name);
|
||||
if (!filename)
|
||||
goto out;
|
||||
char *filepath;
|
||||
struct path parent;
|
||||
size_t path_len, remain_len;
|
||||
|
||||
/* root reached */
|
||||
if (strlen(name) == 0)
|
||||
goto out;
|
||||
filepath = kstrdup(name, GFP_KERNEL);
|
||||
if (!filepath)
|
||||
return -ENOMEM;
|
||||
|
||||
err = ksmbd_vfs_lookup_in_dir(name, filename);
|
||||
path_len = strlen(filepath);
|
||||
remain_len = path_len - 1;
|
||||
|
||||
err = kern_path("/", flags, &parent);
|
||||
if (err)
|
||||
goto out;
|
||||
err = kern_path(name, flags, path);
|
||||
}
|
||||
|
||||
while (d_can_lookup(parent.dentry)) {
|
||||
char *filename = filepath + path_len - remain_len;
|
||||
char *next = strchrnul(filename, '/');
|
||||
size_t filename_len = next - filename;
|
||||
bool is_last = !next[0];
|
||||
|
||||
if (filename_len == 0)
|
||||
break;
|
||||
|
||||
err = ksmbd_vfs_lookup_in_dir(&parent, filename,
|
||||
filename_len);
|
||||
if (err) {
|
||||
path_put(&parent);
|
||||
goto out;
|
||||
}
|
||||
|
||||
path_put(&parent);
|
||||
next[0] = '\0';
|
||||
|
||||
err = kern_path(filepath, flags, &parent);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (is_last) {
|
||||
path->mnt = parent.mnt;
|
||||
path->dentry = parent.dentry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
next[0] = '/';
|
||||
remain_len -= filename_len + 1;
|
||||
}
|
||||
|
||||
path_put(&parent);
|
||||
err = -EINVAL;
|
||||
out:
|
||||
rollback_path_modification(filename);
|
||||
kfree(filepath);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user