diff --git a/docs/src/fs.rst b/docs/src/fs.rst index d6a0e6a3..cc8f5525 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -76,6 +76,7 @@ Data types UV_FS_FTRUNCATE, UV_FS_UTIME, UV_FS_FUTIME, + UV_FS_ACCESS, UV_FS_CHMOD, UV_FS_FCHMOD, UV_FS_FSYNC, @@ -228,6 +229,10 @@ API Limited equivalent to ``sendfile(2)``. +.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) + + Equivalent to ``access(2)`` on Unix. Windows uses ``GetFileAttributesW()``. + .. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) .. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb) diff --git a/include/uv-win.h b/include/uv-win.h index 293b41d0..4abb294c 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -639,3 +639,15 @@ int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, size_t utf16Size); +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif diff --git a/include/uv.h b/include/uv.h index 42c6100a..ad6bde99 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1022,6 +1022,7 @@ typedef enum { UV_FS_FTRUNCATE, UV_FS_UTIME, UV_FS_FUTIME, + UV_FS_ACCESS, UV_FS_CHMOD, UV_FS_FCHMOD, UV_FS_FSYNC, @@ -1134,6 +1135,11 @@ UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, int64_t in_offset, size_t length, uv_fs_cb cb); +UV_EXTERN int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb); UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/unix/fs.c b/src/unix/fs.c index cb8741b0..65fd0123 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -763,6 +763,7 @@ static void uv__fs_work(struct uv__work* w) { break; switch (req->fs_type) { + X(ACCESS, access(req->path, req->flags)); X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); X(CLOSE, close(req->file)); @@ -853,6 +854,18 @@ static void uv__fs_done(struct uv__work* w, int status) { } +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + INIT(ACCESS); + PATH; + req->flags = flags; + POST; +} + + int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/win/fs.c b/src/win/fs.c index 4c319db6..47e65e84 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1220,6 +1220,25 @@ static void fs__sendfile(uv_fs_t* req) { } +static void fs__access(uv_fs_t* req) { + DWORD attr = GetFileAttributesW(req->pathw); + + if (attr == INVALID_FILE_ATTRIBUTES) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if ((req->flags & W_OK) && + ((attr & FILE_ATTRIBUTE_READONLY) || + (attr & FILE_ATTRIBUTE_DIRECTORY))) { + SET_REQ_WIN32_ERROR(req, UV_EPERM); + return; + } + + SET_REQ_RESULT(req, 0); +} + + static void fs__chmod(uv_fs_t* req) { int result = _wchmod(req->pathw, req->mode); SET_REQ_RESULT(req, result); @@ -1595,6 +1614,7 @@ static void uv__fs_work(struct uv__work* w) { XX(FTRUNCATE, ftruncate) XX(UTIME, utime) XX(FUTIME, futime) + XX(ACCESS, access) XX(CHMOD, chmod) XX(FCHMOD, fchmod) XX(FSYNC, fsync) @@ -2102,6 +2122,31 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, } +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_ACCESS, cb); + + err = fs__capture_path(loop, req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + + req->flags = flags; + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } + + fs__access(req); + return req->result; +} + + int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { int err; diff --git a/test/test-fs.c b/test/test-fs.c index db07ed2f..6095ff89 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -75,6 +75,7 @@ static int fdatasync_cb_count; static int ftruncate_cb_count; static int sendfile_cb_count; static int fstat_cb_count; +static int access_cb_count; static int chmod_cb_count; static int fchmod_cb_count; static int chown_cb_count; @@ -164,6 +165,14 @@ static void readlink_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } + +static void access_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_ACCESS); + access_cb_count++; + uv_fs_req_cleanup(req); +} + + static void fchmod_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_FCHMOD); ASSERT(req->result == 0); @@ -1119,6 +1128,70 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_access) { + int r; + uv_fs_t req; + uv_file file; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + /* File should not exist */ + r = uv_fs_access(loop, &req, "test_file", F_OK, NULL); + ASSERT(r < 0); + ASSERT(req.result < 0); + uv_fs_req_cleanup(&req); + + /* File should not exist */ + r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(access_cb_count == 1); + access_cb_count = 0; /* reset for the next test */ + + /* Create file */ + r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + /* File should exist */ + r = uv_fs_access(loop, &req, "test_file", F_OK, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* File should exist */ + r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(access_cb_count == 1); + access_cb_count = 0; /* reset for the next test */ + + /* Close file */ + r = uv_fs_close(loop, &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() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_chmod) { int r; uv_fs_t req; diff --git a/test/test-list.h b/test/test-list.h index 90c0442b..9971c916 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -218,6 +218,7 @@ TEST_DECLARE (fs_async_dir) TEST_DECLARE (fs_async_sendfile) TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_fstat) +TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) @@ -590,6 +591,7 @@ TASK_LIST_START TEST_ENTRY (fs_async_sendfile) TEST_ENTRY (fs_mkdtemp) TEST_ENTRY (fs_fstat) + TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_chown) TEST_ENTRY (fs_utime)