diff --git a/docs/src/fs.rst b/docs/src/fs.rst index e425d4ec..a390f140 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -92,6 +92,7 @@ Data types UV_FS_READLINK, UV_FS_CHOWN, UV_FS_FCHOWN, + UV_FS_LCHOWN, UV_FS_REALPATH, UV_FS_COPYFILE } uv_fs_type; @@ -349,12 +350,15 @@ API .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) .. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) +.. c:function:: int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) - Equivalent to :man:`chown(2)` and :man:`fchown(2)` respectively. + Equivalent to :man:`chown(2)`, :man:`fchown(2)` and :man:`lchown(2)` respectively. .. note:: These functions are not implemented on Windows. + .. versionchanged:: 1.21.0 implemented uv_fs_lchown + .. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) Returns `req->fs_type`. diff --git a/include/uv.h b/include/uv.h index 192f3d9b..91451ada 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1141,6 +1141,7 @@ typedef enum { UV_FS_READLINK, UV_FS_CHOWN, UV_FS_FCHOWN, + UV_FS_LCHOWN, UV_FS_REALPATH, UV_FS_COPYFILE } uv_fs_type; @@ -1345,6 +1346,12 @@ UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); +UV_EXTERN int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); enum uv_fs_event { diff --git a/src/unix/fs.c b/src/unix/fs.c index fcbc6786..652cdfd7 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1120,6 +1120,7 @@ static void uv__fs_work(struct uv__work* w) { X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(LCHOWN, lchown(req->path, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); X(FSYNC, uv__fs_fsync(req)); @@ -1246,6 +1247,20 @@ int uv_fs_fchown(uv_loop_t* loop, } +int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(LCHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FDATASYNC); req->file = file; diff --git a/src/win/fs.c b/src/win/fs.c index 6b050d06..71b6a81a 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1971,6 +1971,10 @@ static void fs__fchown(uv_fs_t* req) { } +static void fs__lchown(uv_fs_t* req) { + req->result = 0; +} + static void uv__fs_work(struct uv__work* w) { uv_fs_t* req; @@ -2008,6 +2012,7 @@ static void uv__fs_work(struct uv__work* w) { XX(REALPATH, realpath) XX(CHOWN, chown) XX(FCHOWN, fchown); + XX(LCHOWN, lchown); default: assert(!"bad uv_fs_type"); } @@ -2293,6 +2298,19 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, } +int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LCHOWN); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + POST; +} + + int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; diff --git a/test/test-fs.c b/test/test-fs.c index 66e78e42..57da3989 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -84,6 +84,7 @@ static int chmod_cb_count; static int fchmod_cb_count; static int chown_cb_count; static int fchown_cb_count; +static int lchown_cb_count; static int link_cb_count; static int symlink_cb_count; static int readlink_cb_count; @@ -253,6 +254,13 @@ static void chown_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void lchown_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_LCHOWN); + ASSERT(req->result == 0); + lchown_cb_count++; + uv_fs_req_cleanup(req); +} + static void chown_root_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_CHOWN); #if defined(_WIN32) || defined(__MSYS__) @@ -1540,6 +1548,7 @@ TEST_IMPL(fs_chown) { /* Setup. */ unlink("test_file"); + unlink("test_file_link"); loop = uv_default_loop(); @@ -1583,7 +1592,29 @@ TEST_IMPL(fs_chown) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(fchown_cb_count == 1); - close(file); + /* sync link */ + r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* sync lchown */ + r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* async lchown */ + r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(lchown_cb_count == 1); + + /* Close file */ + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); /* * Run the loop just to check we don't have make any extraneous uv_ref() @@ -1593,6 +1624,7 @@ TEST_IMPL(fs_chown) { /* Cleanup. */ unlink("test_file"); + unlink("test_file_link"); MAKE_VALGRIND_HAPPY(); return 0;