111aeb714SJens Axboe // SPDX-License-Identifier: GPL-2.0
211aeb714SJens Axboe #include <linux/kernel.h>
311aeb714SJens Axboe #include <linux/errno.h>
411aeb714SJens Axboe #include <linux/fs.h>
511aeb714SJens Axboe #include <linux/file.h>
611aeb714SJens Axboe #include <linux/mm.h>
711aeb714SJens Axboe #include <linux/slab.h>
811aeb714SJens Axboe #include <linux/namei.h>
911aeb714SJens Axboe #include <linux/io_uring.h>
1011aeb714SJens Axboe
1111aeb714SJens Axboe #include <uapi/linux/io_uring.h>
1211aeb714SJens Axboe
1311aeb714SJens Axboe #include "../fs/internal.h"
1411aeb714SJens Axboe
1511aeb714SJens Axboe #include "io_uring.h"
1611aeb714SJens Axboe #include "fs.h"
1711aeb714SJens Axboe
1811aeb714SJens Axboe struct io_rename {
1911aeb714SJens Axboe struct file *file;
2011aeb714SJens Axboe int old_dfd;
2111aeb714SJens Axboe int new_dfd;
2211aeb714SJens Axboe struct filename *oldpath;
2311aeb714SJens Axboe struct filename *newpath;
2411aeb714SJens Axboe int flags;
2511aeb714SJens Axboe };
2611aeb714SJens Axboe
2711aeb714SJens Axboe struct io_unlink {
2811aeb714SJens Axboe struct file *file;
2911aeb714SJens Axboe int dfd;
3011aeb714SJens Axboe int flags;
3111aeb714SJens Axboe struct filename *filename;
3211aeb714SJens Axboe };
3311aeb714SJens Axboe
3411aeb714SJens Axboe struct io_mkdir {
3511aeb714SJens Axboe struct file *file;
3611aeb714SJens Axboe int dfd;
3711aeb714SJens Axboe umode_t mode;
3811aeb714SJens Axboe struct filename *filename;
3911aeb714SJens Axboe };
4011aeb714SJens Axboe
4111aeb714SJens Axboe struct io_link {
4211aeb714SJens Axboe struct file *file;
4311aeb714SJens Axboe int old_dfd;
4411aeb714SJens Axboe int new_dfd;
4511aeb714SJens Axboe struct filename *oldpath;
4611aeb714SJens Axboe struct filename *newpath;
4711aeb714SJens Axboe int flags;
4811aeb714SJens Axboe };
4911aeb714SJens Axboe
io_renameat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)5011aeb714SJens Axboe int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
5111aeb714SJens Axboe {
52f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
5311aeb714SJens Axboe const char __user *oldf, *newf;
5411aeb714SJens Axboe
5511aeb714SJens Axboe if (sqe->buf_index || sqe->splice_fd_in)
5611aeb714SJens Axboe return -EINVAL;
5711aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE))
5811aeb714SJens Axboe return -EBADF;
5911aeb714SJens Axboe
6011aeb714SJens Axboe ren->old_dfd = READ_ONCE(sqe->fd);
6111aeb714SJens Axboe oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
6211aeb714SJens Axboe newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
6311aeb714SJens Axboe ren->new_dfd = READ_ONCE(sqe->len);
6411aeb714SJens Axboe ren->flags = READ_ONCE(sqe->rename_flags);
6511aeb714SJens Axboe
6611aeb714SJens Axboe ren->oldpath = getname(oldf);
6711aeb714SJens Axboe if (IS_ERR(ren->oldpath))
6811aeb714SJens Axboe return PTR_ERR(ren->oldpath);
6911aeb714SJens Axboe
7011aeb714SJens Axboe ren->newpath = getname(newf);
7111aeb714SJens Axboe if (IS_ERR(ren->newpath)) {
7211aeb714SJens Axboe putname(ren->oldpath);
7311aeb714SJens Axboe return PTR_ERR(ren->newpath);
7411aeb714SJens Axboe }
7511aeb714SJens Axboe
7611aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP;
77aebb224fSDylan Yudaken req->flags |= REQ_F_FORCE_ASYNC;
7811aeb714SJens Axboe return 0;
7911aeb714SJens Axboe }
8011aeb714SJens Axboe
io_renameat(struct io_kiocb * req,unsigned int issue_flags)8111aeb714SJens Axboe int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
8211aeb714SJens Axboe {
83f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
8411aeb714SJens Axboe int ret;
8511aeb714SJens Axboe
86aebb224fSDylan Yudaken WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
8711aeb714SJens Axboe
8811aeb714SJens Axboe ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
8911aeb714SJens Axboe ren->newpath, ren->flags);
9011aeb714SJens Axboe
9111aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP;
9211aeb714SJens Axboe io_req_set_res(req, ret, 0);
9311aeb714SJens Axboe return IOU_OK;
9411aeb714SJens Axboe }
9511aeb714SJens Axboe
io_renameat_cleanup(struct io_kiocb * req)9611aeb714SJens Axboe void io_renameat_cleanup(struct io_kiocb *req)
9711aeb714SJens Axboe {
98f2ccb5aeSStefan Metzmacher struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
9911aeb714SJens Axboe
10011aeb714SJens Axboe putname(ren->oldpath);
10111aeb714SJens Axboe putname(ren->newpath);
10211aeb714SJens Axboe }
10311aeb714SJens Axboe
io_unlinkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)10411aeb714SJens Axboe int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
10511aeb714SJens Axboe {
106f2ccb5aeSStefan Metzmacher struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
10711aeb714SJens Axboe const char __user *fname;
10811aeb714SJens Axboe
10911aeb714SJens Axboe if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
11011aeb714SJens Axboe return -EINVAL;
11111aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE))
11211aeb714SJens Axboe return -EBADF;
11311aeb714SJens Axboe
11411aeb714SJens Axboe un->dfd = READ_ONCE(sqe->fd);
11511aeb714SJens Axboe
11611aeb714SJens Axboe un->flags = READ_ONCE(sqe->unlink_flags);
11711aeb714SJens Axboe if (un->flags & ~AT_REMOVEDIR)
11811aeb714SJens Axboe return -EINVAL;
11911aeb714SJens Axboe
12011aeb714SJens Axboe fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
12111aeb714SJens Axboe un->filename = getname(fname);
12211aeb714SJens Axboe if (IS_ERR(un->filename))
12311aeb714SJens Axboe return PTR_ERR(un->filename);
12411aeb714SJens Axboe
12511aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP;
126aebb224fSDylan Yudaken req->flags |= REQ_F_FORCE_ASYNC;
12711aeb714SJens Axboe return 0;
12811aeb714SJens Axboe }
12911aeb714SJens Axboe
io_unlinkat(struct io_kiocb * req,unsigned int issue_flags)13011aeb714SJens Axboe int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
13111aeb714SJens Axboe {
132f2ccb5aeSStefan Metzmacher struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
13311aeb714SJens Axboe int ret;
13411aeb714SJens Axboe
135aebb224fSDylan Yudaken WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
13611aeb714SJens Axboe
13711aeb714SJens Axboe if (un->flags & AT_REMOVEDIR)
13811aeb714SJens Axboe ret = do_rmdir(un->dfd, un->filename);
13911aeb714SJens Axboe else
14011aeb714SJens Axboe ret = do_unlinkat(un->dfd, un->filename);
14111aeb714SJens Axboe
14211aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP;
14311aeb714SJens Axboe io_req_set_res(req, ret, 0);
14411aeb714SJens Axboe return IOU_OK;
14511aeb714SJens Axboe }
14611aeb714SJens Axboe
io_unlinkat_cleanup(struct io_kiocb * req)14711aeb714SJens Axboe void io_unlinkat_cleanup(struct io_kiocb *req)
14811aeb714SJens Axboe {
149f2ccb5aeSStefan Metzmacher struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
15011aeb714SJens Axboe
15111aeb714SJens Axboe putname(ul->filename);
15211aeb714SJens Axboe }
15311aeb714SJens Axboe
io_mkdirat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)15411aeb714SJens Axboe int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
15511aeb714SJens Axboe {
156f2ccb5aeSStefan Metzmacher struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
15711aeb714SJens Axboe const char __user *fname;
15811aeb714SJens Axboe
15911aeb714SJens Axboe if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
16011aeb714SJens Axboe return -EINVAL;
16111aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE))
16211aeb714SJens Axboe return -EBADF;
16311aeb714SJens Axboe
16411aeb714SJens Axboe mkd->dfd = READ_ONCE(sqe->fd);
16511aeb714SJens Axboe mkd->mode = READ_ONCE(sqe->len);
16611aeb714SJens Axboe
16711aeb714SJens Axboe fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
16811aeb714SJens Axboe mkd->filename = getname(fname);
16911aeb714SJens Axboe if (IS_ERR(mkd->filename))
17011aeb714SJens Axboe return PTR_ERR(mkd->filename);
17111aeb714SJens Axboe
17211aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP;
173aebb224fSDylan Yudaken req->flags |= REQ_F_FORCE_ASYNC;
17411aeb714SJens Axboe return 0;
17511aeb714SJens Axboe }
17611aeb714SJens Axboe
io_mkdirat(struct io_kiocb * req,unsigned int issue_flags)17711aeb714SJens Axboe int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
17811aeb714SJens Axboe {
179f2ccb5aeSStefan Metzmacher struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
18011aeb714SJens Axboe int ret;
18111aeb714SJens Axboe
182aebb224fSDylan Yudaken WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
18311aeb714SJens Axboe
18411aeb714SJens Axboe ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
18511aeb714SJens Axboe
18611aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP;
18711aeb714SJens Axboe io_req_set_res(req, ret, 0);
18811aeb714SJens Axboe return IOU_OK;
18911aeb714SJens Axboe }
19011aeb714SJens Axboe
io_mkdirat_cleanup(struct io_kiocb * req)19111aeb714SJens Axboe void io_mkdirat_cleanup(struct io_kiocb *req)
19211aeb714SJens Axboe {
193f2ccb5aeSStefan Metzmacher struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
19411aeb714SJens Axboe
19511aeb714SJens Axboe putname(md->filename);
19611aeb714SJens Axboe }
19711aeb714SJens Axboe
io_symlinkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)19811aeb714SJens Axboe int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
19911aeb714SJens Axboe {
200f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
20111aeb714SJens Axboe const char __user *oldpath, *newpath;
20211aeb714SJens Axboe
20311aeb714SJens Axboe if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
20411aeb714SJens Axboe return -EINVAL;
20511aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE))
20611aeb714SJens Axboe return -EBADF;
20711aeb714SJens Axboe
20811aeb714SJens Axboe sl->new_dfd = READ_ONCE(sqe->fd);
20911aeb714SJens Axboe oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
21011aeb714SJens Axboe newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
21111aeb714SJens Axboe
21211aeb714SJens Axboe sl->oldpath = getname(oldpath);
21311aeb714SJens Axboe if (IS_ERR(sl->oldpath))
21411aeb714SJens Axboe return PTR_ERR(sl->oldpath);
21511aeb714SJens Axboe
21611aeb714SJens Axboe sl->newpath = getname(newpath);
21711aeb714SJens Axboe if (IS_ERR(sl->newpath)) {
21811aeb714SJens Axboe putname(sl->oldpath);
21911aeb714SJens Axboe return PTR_ERR(sl->newpath);
22011aeb714SJens Axboe }
22111aeb714SJens Axboe
22211aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP;
223aebb224fSDylan Yudaken req->flags |= REQ_F_FORCE_ASYNC;
22411aeb714SJens Axboe return 0;
22511aeb714SJens Axboe }
22611aeb714SJens Axboe
io_symlinkat(struct io_kiocb * req,unsigned int issue_flags)22711aeb714SJens Axboe int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
22811aeb714SJens Axboe {
229f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
23011aeb714SJens Axboe int ret;
23111aeb714SJens Axboe
232aebb224fSDylan Yudaken WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
23311aeb714SJens Axboe
23411aeb714SJens Axboe ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
23511aeb714SJens Axboe
23611aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP;
23711aeb714SJens Axboe io_req_set_res(req, ret, 0);
23811aeb714SJens Axboe return IOU_OK;
23911aeb714SJens Axboe }
24011aeb714SJens Axboe
io_linkat_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)24111aeb714SJens Axboe int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
24211aeb714SJens Axboe {
243f2ccb5aeSStefan Metzmacher struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
24411aeb714SJens Axboe const char __user *oldf, *newf;
24511aeb714SJens Axboe
246a52d4f65SJens Axboe if (sqe->buf_index || sqe->splice_fd_in)
24711aeb714SJens Axboe return -EINVAL;
24811aeb714SJens Axboe if (unlikely(req->flags & REQ_F_FIXED_FILE))
24911aeb714SJens Axboe return -EBADF;
25011aeb714SJens Axboe
25111aeb714SJens Axboe lnk->old_dfd = READ_ONCE(sqe->fd);
25211aeb714SJens Axboe lnk->new_dfd = READ_ONCE(sqe->len);
25311aeb714SJens Axboe oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
25411aeb714SJens Axboe newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
25511aeb714SJens Axboe lnk->flags = READ_ONCE(sqe->hardlink_flags);
25611aeb714SJens Axboe
257*ed869aeeSCharles Mirabile lnk->oldpath = getname_uflags(oldf, lnk->flags);
25811aeb714SJens Axboe if (IS_ERR(lnk->oldpath))
25911aeb714SJens Axboe return PTR_ERR(lnk->oldpath);
26011aeb714SJens Axboe
26111aeb714SJens Axboe lnk->newpath = getname(newf);
26211aeb714SJens Axboe if (IS_ERR(lnk->newpath)) {
26311aeb714SJens Axboe putname(lnk->oldpath);
26411aeb714SJens Axboe return PTR_ERR(lnk->newpath);
26511aeb714SJens Axboe }
26611aeb714SJens Axboe
26711aeb714SJens Axboe req->flags |= REQ_F_NEED_CLEANUP;
268aebb224fSDylan Yudaken req->flags |= REQ_F_FORCE_ASYNC;
26911aeb714SJens Axboe return 0;
27011aeb714SJens Axboe }
27111aeb714SJens Axboe
io_linkat(struct io_kiocb * req,unsigned int issue_flags)27211aeb714SJens Axboe int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
27311aeb714SJens Axboe {
274f2ccb5aeSStefan Metzmacher struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
27511aeb714SJens Axboe int ret;
27611aeb714SJens Axboe
277aebb224fSDylan Yudaken WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
27811aeb714SJens Axboe
27911aeb714SJens Axboe ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
28011aeb714SJens Axboe lnk->newpath, lnk->flags);
28111aeb714SJens Axboe
28211aeb714SJens Axboe req->flags &= ~REQ_F_NEED_CLEANUP;
28311aeb714SJens Axboe io_req_set_res(req, ret, 0);
28411aeb714SJens Axboe return IOU_OK;
28511aeb714SJens Axboe }
28611aeb714SJens Axboe
io_link_cleanup(struct io_kiocb * req)28711aeb714SJens Axboe void io_link_cleanup(struct io_kiocb *req)
28811aeb714SJens Axboe {
289f2ccb5aeSStefan Metzmacher struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
29011aeb714SJens Axboe
29111aeb714SJens Axboe putname(sl->oldpath);
29211aeb714SJens Axboe putname(sl->newpath);
29311aeb714SJens Axboe }
294