Initial Linux implementation of uv_fs_openat
This commit adds the initial Linux implementation of `uv_fs_openat`. Windows support using `NtCreateFile` will come in a later commit. fixes #4167 Signed-off-by: Yage Hu <me@huyage.dev>
This commit is contained in:
parent
eb5af8e3c0
commit
f30e015b85
10
include/uv.h
10
include/uv.h
@ -1398,7 +1398,8 @@ typedef enum {
|
||||
UV_FS_CLOSEDIR,
|
||||
UV_FS_STATFS,
|
||||
UV_FS_MKSTEMP,
|
||||
UV_FS_LUTIME
|
||||
UV_FS_LUTIME,
|
||||
UV_FS_OPENAT
|
||||
} uv_fs_type;
|
||||
|
||||
struct uv_dir_s {
|
||||
@ -1439,6 +1440,13 @@ UV_EXTERN int uv_fs_open(uv_loop_t* loop,
|
||||
int flags,
|
||||
int mode,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_openat(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_os_fd_t file,
|
||||
const char* path,
|
||||
int flags,
|
||||
int mode,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_read(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_file file,
|
||||
|
||||
@ -504,6 +504,34 @@ static ssize_t uv__pwritev(int fd,
|
||||
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0);
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_openat(uv_fs_t* req) {
|
||||
#ifdef O_CLOEXEC
|
||||
return openat(req->file, req->path, req->flags | O_CLOEXEC, req->mode);
|
||||
#else /* O_CLOEXEC */
|
||||
int r;
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
|
||||
r = openat(req->file, req->path, req->flags, req->mode);
|
||||
|
||||
/* In case of failure `uv__cloexec` will leave error in `errno`,
|
||||
* so it is enough to just set `r` to `-1`.
|
||||
*/
|
||||
if (r >= 0 && uv__cloexec(r, 1) != 0) {
|
||||
r = uv__close(r);
|
||||
if (r != 0)
|
||||
abort();
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
|
||||
return r;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
const struct iovec* bufs;
|
||||
@ -1718,6 +1746,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(MKDTEMP, uv__fs_mkdtemp(req));
|
||||
X(MKSTEMP, uv__fs_mkstemp(req));
|
||||
X(OPEN, uv__fs_open(req));
|
||||
X(OPENAT, uv__fs_openat(req));
|
||||
X(READ, uv__fs_read(req));
|
||||
X(SCANDIR, uv__fs_scandir(req));
|
||||
X(OPENDIR, uv__fs_opendir(req));
|
||||
@ -2013,6 +2042,24 @@ int uv_fs_open(uv_loop_t* loop,
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_openat(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_os_fd_t file,
|
||||
const char* path,
|
||||
int flags,
|
||||
int mode,
|
||||
uv_fs_cb cb) {
|
||||
INIT(OPENAT);
|
||||
PATH;
|
||||
req->file = file;
|
||||
req->flags = flags;
|
||||
req->mode = mode;
|
||||
if (cb != NULL)
|
||||
if (uv__iou_fs_openat(loop, req))
|
||||
return 0;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
|
||||
uv_file file,
|
||||
|
||||
@ -338,6 +338,7 @@ int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop,
|
||||
int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_openat(uv_loop_t* loop, uv_fs_t* req);
|
||||
int uv__iou_fs_read_or_write(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
int is_read);
|
||||
@ -354,6 +355,7 @@ int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req);
|
||||
#define uv__iou_fs_link(loop, req) 0
|
||||
#define uv__iou_fs_mkdir(loop, req) 0
|
||||
#define uv__iou_fs_open(loop, req) 0
|
||||
#define uv__iou_fs_openat(loop, req) 0
|
||||
#define uv__iou_fs_read_or_write(loop, req, is_read) 0
|
||||
#define uv__iou_fs_rename(loop, req) 0
|
||||
#define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0
|
||||
|
||||
@ -948,6 +948,28 @@ int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
int uv__iou_fs_openat(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
iou = &uv__get_internal_fields(loop)->iou;
|
||||
|
||||
sqe = uv__iou_get_sqe(iou, loop, req);
|
||||
if (sqe == NULL)
|
||||
return 0;
|
||||
|
||||
sqe->addr = (uintptr_t) req->path;
|
||||
sqe->fd = req->file;
|
||||
sqe->len = req->mode;
|
||||
sqe->opcode = UV__IORING_OP_OPENAT;
|
||||
sqe->open_flags = req->flags | O_CLOEXEC;
|
||||
|
||||
uv__iou_submit(iou);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req) {
|
||||
struct uv__io_uring_sqe* sqe;
|
||||
struct uv__iou* iou;
|
||||
|
||||
@ -3006,6 +3006,60 @@ TEST_IMPL(fs_scandir_early_exit) {
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_openat) {
|
||||
uv_fs_t req;
|
||||
int r;
|
||||
uv_os_fd_t fd;
|
||||
uv_os_fd_t dirfd;
|
||||
|
||||
/* Setup. */
|
||||
unlink("test/fixtures/test_dir/test_file");
|
||||
rmdir("test/fixtures/test_dir");
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
r = uv_fs_mkdir(NULL, &req, "test/fixtures/test_dir", 0755, NULL);
|
||||
ASSERT_OK(r);
|
||||
|
||||
r = uv_fs_open(NULL,
|
||||
&req,
|
||||
"test/fixtures/test_dir",
|
||||
UV_FS_O_RDONLY | UV_FS_O_DIRECTORY,
|
||||
0,
|
||||
NULL);
|
||||
ASSERT_GE(r, 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
dirfd = (uv_os_fd_t) req.result;
|
||||
|
||||
r = uv_fs_openat(NULL,
|
||||
&req,
|
||||
dirfd,
|
||||
"test_file",
|
||||
UV_FS_O_RDWR | UV_FS_O_CREAT,
|
||||
S_IWUSR | S_IRUSR,
|
||||
NULL);
|
||||
ASSERT_GE(r, 0);
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
fd = (uv_os_fd_t) req.result;
|
||||
|
||||
r = uv_fs_close(NULL, &req, dirfd, NULL);
|
||||
ASSERT_OK(r);
|
||||
uv_fs_req_cleanup(&req);
|
||||
r = uv_fs_close(NULL, &req, fd, NULL);
|
||||
ASSERT_OK(r);
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
/* Cleanup */
|
||||
unlink("test/fixtures/test_dir/test_file");
|
||||
rmdir("test/fixtures/test_dir");
|
||||
|
||||
MAKE_VALGRIND_HAPPY(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(fs_open_dir) {
|
||||
const char* path;
|
||||
uv_fs_t req;
|
||||
|
||||
@ -420,6 +420,7 @@ TEST_DECLARE (fs_scandir_empty_dir)
|
||||
TEST_DECLARE (fs_scandir_non_existent_dir)
|
||||
TEST_DECLARE (fs_scandir_file)
|
||||
TEST_DECLARE (fs_scandir_early_exit)
|
||||
TEST_DECLARE (fs_openat)
|
||||
TEST_DECLARE (fs_open_dir)
|
||||
TEST_DECLARE (fs_readdir_empty_dir)
|
||||
TEST_DECLARE (fs_readdir_file)
|
||||
@ -1127,6 +1128,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (fs_scandir_non_existent_dir)
|
||||
TEST_ENTRY (fs_scandir_file)
|
||||
TEST_ENTRY (fs_scandir_early_exit)
|
||||
TEST_ENTRY (fs_openat)
|
||||
TEST_ENTRY (fs_open_dir)
|
||||
TEST_ENTRY (fs_readdir_empty_dir)
|
||||
TEST_ENTRY (fs_readdir_file)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user