Skip to content
Browse files

windows: uv_fs_link + uv_fs_symlink

  • Loading branch information...
1 parent 6422a14 commit 37cfb5e7e93d6f75ff12b5e122e3719168bb363c Igor Zinkovsky committed Sep 3, 2011
Showing with 357 additions and 9 deletions.
  1. +1 −0 include/uv-private/uv-win.h
  2. +3 −1 include/uv.h
  3. +1 −1 src/unix/fs.c
  4. +132 −7 src/win/fs.c
  5. +4 −0 src/win/winapi.c
  6. +8 −0 src/win/winapi.h
  7. +204 −0 test/test-fs.c
  8. +4 −0 test/test-list.h
View
1 include/uv-private/uv-win.h
@@ -247,6 +247,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
#define UV_FS_PRIVATE_FIELDS \
int flags; \
+ int last_error; \
struct _stat stat; \
void* arg0; \
union { \
View
4 include/uv.h
@@ -894,6 +894,8 @@ struct uv_fs_s {
UV_FS_PRIVATE_FIELDS
};
+#define UV_FS_SYMLINK_DIR 0x0001
+
void uv_fs_req_cleanup(uv_fs_t* req);
int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
@@ -949,7 +951,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb);
int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, uv_fs_cb cb);
+ const char* new_path, int flags, uv_fs_cb cb);
int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb);
View
2 src/unix/fs.c
@@ -490,7 +490,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, uv_fs_cb cb) {
+ const char* new_path, int flags, uv_fs_cb cb) {
WRAP_EIO(UV_FS_SYMLINK, eio_symlink, symlink, ARGS2(path, new_path))
}
View
139 src/win/fs.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <malloc.h>
#include <direct.h>
+#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
@@ -36,6 +37,7 @@
#define UV_FS_FREE_ARG1 0x0004
#define UV_FS_FREE_PTR 0x0008
#define UV_FS_CLEANEDUP 0x0010
+#define UV_FS_LAST_ERROR_SET 0x0020
#define STRDUP_ARG(req, i) \
req->arg##i = (void*)strdup((const char*)req->arg##i); \
@@ -70,6 +72,16 @@
uv_ref((loop));
+#define SET_UV_LAST_ERROR_FROM_REQ(req) \
+ if (req->flags & UV_FS_LAST_ERROR_SET) { \
+ uv_set_sys_error(req->loop, req->last_error); \
+ }
+
+#define SET_REQ_LAST_ERROR(req, error) \
+ req->last_error = error; \
+ req->flags |= UV_FS_LAST_ERROR_SET;
+
+
void uv_fs_init() {
_fmode = _O_BINARY;
}
@@ -86,6 +98,7 @@ static void uv_fs_req_init_async(uv_loop_t* loop, uv_fs_t* req,
req->result = 0;
req->ptr = NULL;
req->errorno = 0;
+ req->last_error = 0;
memset(&req->overlapped, 0, sizeof(req->overlapped));
}
@@ -187,6 +200,7 @@ void fs__readdir(uv_fs_t* req, const char* path, int flags) {
if(dir == INVALID_HANDLE_VALUE) {
result = -1;
+ SET_REQ_LAST_ERROR(req, GetLastError());
goto done;
}
@@ -267,6 +281,9 @@ void fs__rename(uv_fs_t* req, const char* path, const char* new_path) {
void fs__fsync(uv_fs_t* req, uv_file file) {
int result = FlushFileBuffers((HANDLE)_get_osfhandle(file)) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_LAST_ERROR(req, GetLastError());
+ }
SET_REQ_RESULT(req, result);
}
@@ -383,6 +400,50 @@ void fs__futime(uv_fs_t* req, uv_file file, double atime, double mtime) {
}
+void fs__link(uv_fs_t* req, const char* path, const char* new_path) {
+ int result = CreateHardLinkA(new_path, path, NULL) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_LAST_ERROR(req, GetLastError());
+ }
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__symlink(uv_fs_t* req, const char* path, const char* new_path,
+ int flags) {
+ int result;
+ if (pCreateSymbolicLinkA) {
+ result = pCreateSymbolicLinkA(new_path,
+ path,
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_LAST_ERROR(req, GetLastError());
+ }
+ } else {
+ result = -1;
+ errno = ENOTSUP;
+ }
+
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__readlink(uv_fs_t* req, const char* path) {
+ int result = -1;
+ assert(0 && "implement me");
+
+ /* TODO: the link path must be returned in a req->ptr buffer,
+ * which need to be alloce'd here.
+ * Just do this (it'll take care of freeing the buffer).
+ * req->ptr = malloc(...);
+ * req->flags |= UV_FS_FREE_PTR;
+ * Also result needs to contain the length of the string.
+ */
+
+ SET_REQ_RESULT(req, result);
+}
+
+
void fs__nop(uv_fs_t* req) {
req->result = 0;
}
@@ -464,6 +525,15 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
case UV_FS_FUTIME:
fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5);
break;
+ case UV_FS_LINK:
+ fs__link(req, (const char*)req->arg0, (const char*)req->arg1);
+ break;
+ case UV_FS_SYMLINK:
+ fs__symlink(req, (const char*)req->arg0, (const char*)req->arg1, (int)req->arg2);
+ break;
+ case UV_FS_READLINK:
+ fs__readlink(req, (const char*)req->arg0);
+ break;
case UV_FS_CHOWN:
case UV_FS_FCHOWN:
fs__nop(req);
@@ -488,6 +558,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_OPEN);
fs__open(req, path, flags, mode);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -502,6 +573,7 @@ int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CLOSE);
fs__close(req, file);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -517,6 +589,7 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_READ);
fs__read(req, file, buf, length, offset);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -532,6 +605,7 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_WRITE);
fs__write(req, file, buf, length, offset);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -548,6 +622,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_UNLINK);
fs__unlink(req, path);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -564,6 +639,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_MKDIR);
fs__mkdir(req, path, mode);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -579,6 +655,7 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
} else {
uv_fs_req_init_sync(loop, req, UV_FS_RMDIR);
fs__rmdir(req, path);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -595,6 +672,7 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_READDIR);
fs__readdir(req, path, flags);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -603,22 +681,54 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
const char* new_path, uv_fs_cb cb) {
- assert(0 && "implement me");
- return -1;
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_LINK, cb);
+ WRAP_REQ_ARGS2(req, path, new_path);
+ STRDUP_ARG(req, 0);
+ STRDUP_ARG(req, 1);
+ QUEUE_FS_TP_JOB(loop, req);
+ } else {
+ uv_fs_req_init_sync(loop, req, UV_FS_LINK);
+ fs__link(req, path, new_path);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
+ }
+
+ return 0;
}
int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, uv_fs_cb cb) {
- assert(0 && "implement me");
- return -1;
+ const char* new_path, int flags, uv_fs_cb cb) {
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_SYMLINK, cb);
+ WRAP_REQ_ARGS3(req, path, new_path, flags);
+ STRDUP_ARG(req, 0);
+ STRDUP_ARG(req, 1);
+ QUEUE_FS_TP_JOB(loop, req);
+ } else {
+ uv_fs_req_init_sync(loop, req, UV_FS_SYMLINK);
+ fs__symlink(req, path, new_path, flags);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
+ }
+
+ return 0;
}
int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
uv_fs_cb cb) {
- assert(0 && "implement me");
- return -1;
+ if (cb) {
+ uv_fs_req_init_async(loop, req, UV_FS_READLINK, cb);
+ WRAP_REQ_ARGS1(req, path);
+ STRDUP_ARG(req, 0);
+ QUEUE_FS_TP_JOB(loop, req);
+ } else {
+ uv_fs_req_init_sync(loop, req, UV_FS_READLINK);
+ fs__readlink(req, path);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
+ }
+
+ return 0;
}
@@ -632,6 +742,7 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CHOWN);
fs__nop(req);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -647,6 +758,7 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, int uid,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FCHOWN);
fs__nop(req);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -684,6 +796,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
if (path2) {
free(path2);
}
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -722,6 +835,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
if (path2) {
free(path2);
}
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -736,6 +850,7 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FSTAT);
fs__fstat(req, file);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -753,6 +868,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_RENAME);
fs__rename(req, path, new_path);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -767,6 +883,7 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FDATASYNC);
fs__fsync(req, file);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -781,6 +898,7 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FSYNC);
fs__fsync(req, file);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -796,6 +914,7 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FTRUNCATE);
fs__ftruncate(req, file, offset);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -811,6 +930,7 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_SENDFILE);
fs__sendfile(req, out_fd, in_fd, in_offset, length);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -827,6 +947,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_CHMOD);
fs__chmod(req, path, mode);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -842,6 +963,7 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FCHMOD);
fs__fchmod(req, file, mode);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -860,6 +982,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_UTIME);
fs__utime(req, path, atime, mtime);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -877,6 +1000,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
} else {
uv_fs_req_init_sync(loop, req, UV_FS_FUTIME);
fs__futime(req, file, atime, mtime);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
}
return 0;
@@ -885,6 +1009,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
assert(req->cb);
+ SET_UV_LAST_ERROR_FROM_REQ(req);
req->cb(req);
}
View
4 src/win/winapi.c
@@ -31,6 +31,7 @@ sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+sCreateSymbolicLinkA pCreateSymbolicLinkA;
void uv_winapi_init() {
@@ -74,4 +75,7 @@ void uv_winapi_init() {
pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
+
+ pCreateSymbolicLinkA = (sCreateSymbolicLinkA)
+ GetProcAddress(kernel32_module, "CreateSymbolicLinkA");
}
View
8 src/win/winapi.h
@@ -4186,6 +4186,8 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile)
#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+
#ifdef __MINGW32__
typedef struct _OVERLAPPED_ENTRY {
ULONG_PTR lpCompletionKey;
@@ -4207,6 +4209,11 @@ typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
(HANDLE FileHandle,
UCHAR Flags);
+typedef BOOLEAN (WINAPI* sCreateSymbolicLinkA)
+ (LPCSTR lpSymlinkFileName,
+ LPCSTR lpTargetFileName,
+ DWORD dwFlags);
+
/* Ntapi function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4217,5 +4224,6 @@ extern sNtSetInformationFile pNtSetInformationFile;
/* Kernel32 function pointers */
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+extern sCreateSymbolicLinkA pCreateSymbolicLinkA;
#endif /* UV_WIN_WINAPI_H_ */
View
204 test/test-fs.c
@@ -25,6 +25,7 @@
#include "uv.h"
#include "task.h"
+#include <errno.h>
#include <string.h> /* memset */
#include <fcntl.h>
#include <sys/stat.h>
@@ -62,6 +63,8 @@ static int chmod_cb_count;
static int fchmod_cb_count;
static int chown_cb_count;
static int fchown_cb_count;
+static int link_cb_count;
+static int symlink_cb_count;
static uv_loop_t* loop;
@@ -109,6 +112,22 @@ void check_permission(const char* filename, int mode) {
}
+static void link_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_LINK);
+ ASSERT(req->result == 0);
+ link_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void symlink_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_SYMLINK);
+ ASSERT(req->result == 0);
+ symlink_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);
@@ -820,4 +839,189 @@ TEST_IMPL(fs_chown) {
unlink("test_file");
return 0;
+}
+
+
+TEST_IMPL(fs_link) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ uv_init();
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWRITE | S_IREAD, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync link */
+ r = uv_fs_link(loop, &req, "test_file", "test_file_link", NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "test_file_link", O_RDWR, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /* async link */
+ r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
+ ASSERT(r == 0);
+ uv_run(loop);
+ ASSERT(link_cb_count == 1);
+
+ r = uv_fs_open(loop, &req, "test_file_link2", O_RDWR, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ return 0;
+}
+
+
+TEST_IMPL(fs_symlink) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink2");
+
+ uv_init();
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWRITE | S_IREAD, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_write(loop, &req, file, test_buf, sizeof(test_buf), -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync symlink */
+ r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink", 0, NULL);
+ ASSERT(r == 0);
+#ifdef _WIN32
+ if (req.result == -1) {
+ if (req.errorno == ENOTSUP) {
+ /*
+ * Windows doesn't support symlinks on older versions.
+ * We just pass the test and bail out early if we get ENOTSUP.
+ */
+ return 0;
+ } else if (uv_last_error(loop).sys_errno_ == ERROR_PRIVILEGE_NOT_HELD) {
+ /*
+ * Creating a symlink is only allowed when running elevated.
+ * We pass the test and bail out early if we get ERROR_PRIVILEGE_NOT_HELD.
+ */
+ return 0;
+ }
+ }
+#endif
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "test_file_symlink", O_RDWR, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /* async link */
+ r = uv_fs_symlink(loop, &req, "test_file", "test_file_symlink2", 0, symlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop);
+ ASSERT(symlink_cb_count == 1);
+
+ r = uv_fs_open(loop, &req, "test_file_symlink2", O_RDWR, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ r = uv_fs_read(loop, &req, link, buf, sizeof(buf), 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result != -1);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink2");
+
+ return 0;
}
View
4 test/test-list.h
@@ -79,6 +79,8 @@ TEST_DECLARE (fs_async_sendfile)
TEST_DECLARE (fs_fstat)
TEST_DECLARE (fs_chmod)
TEST_DECLARE (fs_chown)
+TEST_DECLARE (fs_link)
+TEST_DECLARE (fs_symlink)
TEST_DECLARE (threadpool_queue_work_simple)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
@@ -185,6 +187,8 @@ TASK_LIST_START
TEST_ENTRY (fs_fstat)
TEST_ENTRY (fs_chmod)
TEST_ENTRY (fs_chown)
+ TEST_ENTRY (fs_link)
+ TEST_ENTRY (fs_symlink)
TEST_ENTRY (threadpool_queue_work_simple)

0 comments on commit 37cfb5e

Please sign in to comment.
Something went wrong with that request. Please try again.