feat: upgrade libuv from 1.34.2 to 1.38.0 with new API and platform fixes
Add uv_library_shutdown() and uv__threadpool_cleanup() functions, introduce UV_UDP_MMSG_CHUNK and UV_UDP_RECVMMSG flags, document cpu_times fields in milliseconds, adjust priority constants for IBM i PASE, widen ansi_parser_state to unsigned short on Windows, refactor async spin loop with sched_yield() and eventfd support on Linux, add ARM yield in cpu_relax(), implement uv__process_title_cleanup() on BSD and Darwin, replace CoreFoundation dependency with darwin-stub.h, and fix accept4 detection for FreeBSD ≥10.
This commit is contained in:
Vendored
+6
-6
@@ -449,12 +449,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
success = GetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
Vendored
+1
@@ -72,6 +72,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case ERROR_NOACCESS: return UV_EACCES;
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
|
||||
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
|
||||
Vendored
+26
-7
@@ -83,6 +83,7 @@ static void uv_relative_path(const WCHAR* filename,
|
||||
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
WCHAR** file) {
|
||||
size_t len, i;
|
||||
DWORD dir_len;
|
||||
|
||||
if (filename == NULL) {
|
||||
if (dir != NULL)
|
||||
@@ -97,12 +98,16 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
|
||||
if (i == 0) {
|
||||
if (dir) {
|
||||
*dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
|
||||
dir_len = GetCurrentDirectoryW(0, NULL);
|
||||
if (dir_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
|
||||
if (!*dir) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
|
||||
if (!GetCurrentDirectoryW(dir_len, *dir)) {
|
||||
uv__free(*dir);
|
||||
*dir = NULL;
|
||||
return -1;
|
||||
@@ -155,9 +160,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
int name_size, is_path_dir, size;
|
||||
DWORD attr, last_error;
|
||||
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
|
||||
WCHAR short_path_buffer[MAX_PATH];
|
||||
DWORD short_path_buffer_len;
|
||||
WCHAR *short_path_buffer;
|
||||
WCHAR* short_path, *long_path;
|
||||
|
||||
short_path = NULL;
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
@@ -230,13 +237,23 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
*/
|
||||
|
||||
/* Convert to short path. */
|
||||
short_path_buffer = NULL;
|
||||
short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
|
||||
if (short_path_buffer_len == 0) {
|
||||
goto short_path_done;
|
||||
}
|
||||
short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
|
||||
if (short_path_buffer == NULL) {
|
||||
goto short_path_done;
|
||||
}
|
||||
if (GetShortPathNameW(pathw,
|
||||
short_path_buffer,
|
||||
ARRAY_SIZE(short_path_buffer))) {
|
||||
short_path = short_path_buffer;
|
||||
} else {
|
||||
short_path = NULL;
|
||||
short_path_buffer_len) == 0) {
|
||||
uv__free(short_path_buffer);
|
||||
short_path_buffer = NULL;
|
||||
}
|
||||
short_path_done:
|
||||
short_path = short_path_buffer;
|
||||
|
||||
if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
|
||||
last_error = GetLastError();
|
||||
@@ -346,6 +363,8 @@ error:
|
||||
if (uv__is_active(handle))
|
||||
uv__handle_stop(handle);
|
||||
|
||||
uv__free(short_path);
|
||||
|
||||
return uv_translate_sys_error(last_error);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+232
-49
@@ -257,6 +257,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
|
||||
req->loop = loop;
|
||||
req->flags = 0;
|
||||
req->fs_type = fs_type;
|
||||
req->sys_errno_ = 0;
|
||||
req->result = 0;
|
||||
req->ptr = NULL;
|
||||
req->path = NULL;
|
||||
@@ -321,6 +322,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
|
||||
WCHAR* w_target;
|
||||
DWORD w_target_len;
|
||||
DWORD bytes;
|
||||
size_t i;
|
||||
size_t len;
|
||||
|
||||
if (!DeviceIoControl(handle,
|
||||
FSCTL_GET_REPARSE_POINT,
|
||||
@@ -405,6 +408,38 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
|
||||
w_target += 4;
|
||||
w_target_len -= 4;
|
||||
|
||||
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
|
||||
/* String #3 in the list has the target filename. */
|
||||
if (reparse_data->AppExecLinkReparseBuffer.StringCount < 3) {
|
||||
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
w_target = reparse_data->AppExecLinkReparseBuffer.StringList;
|
||||
/* The StringList buffer contains a list of strings separated by "\0", */
|
||||
/* with "\0\0" terminating the list. Move to the 3rd string in the list: */
|
||||
for (i = 0; i < 2; ++i) {
|
||||
len = wcslen(w_target);
|
||||
if (len == 0) {
|
||||
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
w_target += len + 1;
|
||||
}
|
||||
w_target_len = wcslen(w_target);
|
||||
if (w_target_len == 0) {
|
||||
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
/* Make sure it is an absolute path. */
|
||||
if (!(w_target_len >= 3 &&
|
||||
((w_target[0] >= L'a' && w_target[0] <= L'z') ||
|
||||
(w_target[0] >= L'A' && w_target[0] <= L'Z')) &&
|
||||
w_target[1] == L':' &&
|
||||
w_target[2] == L'\\')) {
|
||||
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Reparse tag does not indicate a symlink. */
|
||||
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
@@ -2225,34 +2260,68 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void fs__utime(uv_fs_t* req) {
|
||||
INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
|
||||
double atime,
|
||||
double mtime,
|
||||
int do_lutime) {
|
||||
HANDLE handle;
|
||||
DWORD flags;
|
||||
DWORD ret;
|
||||
|
||||
handle = CreateFileW(req->file.pathw,
|
||||
flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (do_lutime) {
|
||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
}
|
||||
|
||||
handle = CreateFileW(path,
|
||||
FILE_WRITE_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
flags,
|
||||
NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
ret = GetLastError();
|
||||
} else if (fs__utime_handle(handle, atime, mtime) != 0) {
|
||||
ret = GetLastError();
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
|
||||
DWORD error;
|
||||
|
||||
error = fs__utime_impl_from_path(req->file.pathw,
|
||||
req->fs.time.atime,
|
||||
req->fs.time.mtime,
|
||||
do_lutime);
|
||||
|
||||
if (error != 0) {
|
||||
if (do_lutime &&
|
||||
(error == ERROR_SYMLINK_NOT_SUPPORTED ||
|
||||
error == ERROR_NOT_A_REPARSE_POINT)) {
|
||||
/* Opened file is a reparse point but not a symlink. Try again. */
|
||||
fs__utime_impl(req, 0);
|
||||
} else {
|
||||
/* utime failed. */
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
req->result = 0;
|
||||
}
|
||||
|
||||
static void fs__utime(uv_fs_t* req) {
|
||||
fs__utime_impl(req, /* do_lutime */ 0);
|
||||
}
|
||||
|
||||
|
||||
static void fs__futime(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
@@ -2274,6 +2343,10 @@ static void fs__futime(uv_fs_t* req) {
|
||||
req->result = 0;
|
||||
}
|
||||
|
||||
static void fs__lutime(uv_fs_t* req) {
|
||||
fs__utime_impl(req, /* do_lutime */ 1);
|
||||
}
|
||||
|
||||
|
||||
static void fs__link(uv_fs_t* req) {
|
||||
DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
|
||||
@@ -2621,14 +2694,62 @@ static void fs__statfs(uv_fs_t* req) {
|
||||
DWORD bytes_per_sector;
|
||||
DWORD free_clusters;
|
||||
DWORD total_clusters;
|
||||
WCHAR* pathw;
|
||||
|
||||
if (0 == GetDiskFreeSpaceW(req->file.pathw,
|
||||
pathw = req->file.pathw;
|
||||
retry_get_disk_free_space:
|
||||
if (0 == GetDiskFreeSpaceW(pathw,
|
||||
§ors_per_cluster,
|
||||
&bytes_per_sector,
|
||||
&free_clusters,
|
||||
&total_clusters)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
DWORD err;
|
||||
WCHAR* fpart;
|
||||
size_t len;
|
||||
DWORD ret;
|
||||
BOOL is_second;
|
||||
|
||||
err = GetLastError();
|
||||
is_second = pathw != req->file.pathw;
|
||||
if (err != ERROR_DIRECTORY || is_second) {
|
||||
if (is_second)
|
||||
uv__free(pathw);
|
||||
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return;
|
||||
}
|
||||
|
||||
len = MAX_PATH + 1;
|
||||
pathw = uv__malloc(len * sizeof(*pathw));
|
||||
if (pathw == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return;
|
||||
}
|
||||
retry_get_full_path_name:
|
||||
ret = GetFullPathNameW(req->file.pathw,
|
||||
len,
|
||||
pathw,
|
||||
&fpart);
|
||||
if (ret == 0) {
|
||||
uv__free(pathw);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return;
|
||||
} else if (ret > len) {
|
||||
len = ret;
|
||||
pathw = uv__reallocf(pathw, len * sizeof(*pathw));
|
||||
if (pathw == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return;
|
||||
}
|
||||
goto retry_get_full_path_name;
|
||||
}
|
||||
if (fpart != 0)
|
||||
*fpart = L'\0';
|
||||
|
||||
goto retry_get_disk_free_space;
|
||||
}
|
||||
if (pathw != req->file.pathw) {
|
||||
uv__free(pathw);
|
||||
}
|
||||
|
||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||
@@ -2670,6 +2791,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(FTRUNCATE, ftruncate)
|
||||
XX(UTIME, utime)
|
||||
XX(FUTIME, futime)
|
||||
XX(LUTIME, lutime)
|
||||
XX(ACCESS, access)
|
||||
XX(CHMOD, chmod)
|
||||
XX(FCHMOD, fchmod)
|
||||
@@ -2753,7 +2875,8 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
INIT(UV_FS_OPEN);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.file_flags = flags;
|
||||
@@ -2778,8 +2901,10 @@ int uv_fs_read(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
INIT(UV_FS_READ);
|
||||
|
||||
if (bufs == NULL || nbufs == 0)
|
||||
if (bufs == NULL || nbufs == 0) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
req->file.fd = fd;
|
||||
|
||||
@@ -2788,8 +2913,10 @@ int uv_fs_read(uv_loop_t* loop,
|
||||
if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
|
||||
req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
|
||||
|
||||
if (req->fs.info.bufs == NULL)
|
||||
if (req->fs.info.bufs == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
|
||||
|
||||
@@ -2807,8 +2934,10 @@ int uv_fs_write(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
INIT(UV_FS_WRITE);
|
||||
|
||||
if (bufs == NULL || nbufs == 0)
|
||||
if (bufs == NULL || nbufs == 0) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
req->file.fd = fd;
|
||||
|
||||
@@ -2817,8 +2946,10 @@ int uv_fs_write(uv_loop_t* loop,
|
||||
if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
|
||||
req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
|
||||
|
||||
if (req->fs.info.bufs == NULL)
|
||||
if (req->fs.info.bufs == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
|
||||
|
||||
@@ -2834,7 +2965,8 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_UNLINK);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -2848,7 +2980,8 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
INIT(UV_FS_MKDIR);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.mode = mode;
|
||||
@@ -2864,8 +2997,10 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_MKDTEMP);
|
||||
err = fs__capture_path(req, tpl, NULL, TRUE);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
}
|
||||
@@ -2879,8 +3014,10 @@ int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_MKSTEMP);
|
||||
err = fs__capture_path(req, tpl, NULL, TRUE);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
}
|
||||
@@ -2892,7 +3029,8 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
INIT(UV_FS_RMDIR);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -2906,7 +3044,8 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
INIT(UV_FS_SCANDIR);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.file_flags = flags;
|
||||
@@ -2921,8 +3060,10 @@ int uv_fs_opendir(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_OPENDIR);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
POST;
|
||||
}
|
||||
|
||||
@@ -2935,6 +3076,7 @@ int uv_fs_readdir(uv_loop_t* loop,
|
||||
if (dir == NULL ||
|
||||
dir->dirents == NULL ||
|
||||
dir->dir_handle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
@@ -2947,8 +3089,10 @@ int uv_fs_closedir(uv_loop_t* loop,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
INIT(UV_FS_CLOSEDIR);
|
||||
if (dir == NULL)
|
||||
if (dir == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
req->ptr = dir;
|
||||
POST;
|
||||
}
|
||||
@@ -2960,7 +3104,8 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_LINK);
|
||||
err = fs__capture_path(req, path, new_path, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -2974,7 +3119,8 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_SYMLINK);
|
||||
err = fs__capture_path(req, path, new_path, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.file_flags = flags;
|
||||
@@ -2989,7 +3135,8 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_READLINK);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3003,12 +3150,14 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_REALPATH);
|
||||
|
||||
if (!path) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3022,7 +3171,8 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
INIT(UV_FS_CHOWN);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3043,8 +3193,10 @@ int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
INIT(UV_FS_LCHOWN);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
}
|
||||
|
||||
@@ -3055,7 +3207,8 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
INIT(UV_FS_STAT);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3068,7 +3221,8 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
INIT(UV_FS_LSTAT);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3089,7 +3243,8 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
INIT(UV_FS_RENAME);
|
||||
err = fs__capture_path(req, path, new_path, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
@@ -3132,13 +3287,15 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
if (flags & ~(UV_FS_COPYFILE_EXCL |
|
||||
UV_FS_COPYFILE_FICLONE |
|
||||
UV_FS_COPYFILE_FICLONE_FORCE)) {
|
||||
SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
err = fs__capture_path(req, path, new_path, cb != NULL);
|
||||
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.file_flags = flags;
|
||||
POST;
|
||||
@@ -3165,8 +3322,10 @@ int uv_fs_access(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_ACCESS);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.mode = flags;
|
||||
POST;
|
||||
@@ -3180,7 +3339,8 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
INIT(UV_FS_CHMOD);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.info.mode = mode;
|
||||
@@ -3204,7 +3364,8 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
INIT(UV_FS_UTIME);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.time.atime = atime;
|
||||
@@ -3222,6 +3383,22 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
|
||||
double mtime, uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LUTIME);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
req->fs.time.atime = atime;
|
||||
req->fs.time.mtime = mtime;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
@@ -3231,8 +3408,14 @@ int uv_fs_statfs(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_STATFS);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
if (err) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
return req->result;
|
||||
}
|
||||
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_get_system_error(const uv_fs_t* req) {
|
||||
return req->sys_errno_;
|
||||
}
|
||||
|
||||
Vendored
+80
-71
@@ -264,8 +264,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
DWORD current_mode = 0;
|
||||
DWORD err = 0;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
|
||||
handle->handle != INVALID_HANDLE_VALUE)
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER)
|
||||
return UV_EINVAL;
|
||||
if (handle->handle != INVALID_HANDLE_VALUE)
|
||||
return UV_EBUSY;
|
||||
|
||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||
@@ -312,7 +313,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
/* Overlapped pipe. Try to associate with IOCP. */
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
handle->flags |= UV_HANDLE_EMULATE_IOCP;
|
||||
}
|
||||
@@ -326,6 +327,38 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
static int pipe_alloc_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle =
|
||||
CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC |
|
||||
(firstInstance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Associate it with IOCP so we can get events. */
|
||||
if (CreateIoCompletionPort(req->pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
|
||||
}
|
||||
|
||||
/* Stash a handle in the server object for use from places such as
|
||||
* getsockname and chmod. As we transfer ownership of these to client
|
||||
* objects, we'll allocate new ones here. */
|
||||
handle->handle = req->pipeHandle;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
||||
uv_loop_t* loop;
|
||||
uv_pipe_t* handle;
|
||||
@@ -458,7 +491,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -540,13 +573,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
* Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
|
||||
* If this fails then there's already a pipe server for the given pipe name.
|
||||
*/
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
if (!pipe_alloc_accept(loop,
|
||||
handle,
|
||||
&handle->pipe.serv.accept_reqs[0],
|
||||
TRUE)) {
|
||||
err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
|
||||
@@ -556,15 +586,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop,
|
||||
handle,
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle,
|
||||
-1,
|
||||
0)) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->pipe.serv.pending_accepts = NULL;
|
||||
handle->flags |= UV_HANDLE_PIPESERVER;
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
@@ -577,11 +598,6 @@ error:
|
||||
handle->name = NULL;
|
||||
}
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -827,29 +843,11 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(handle->flags & UV_HANDLE_LISTENING);
|
||||
|
||||
if (!firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
|
||||
CloseHandle(req->pipeHandle);
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
|
||||
@@ -904,7 +902,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
uv__free(item);
|
||||
|
||||
} else {
|
||||
pipe_client = (uv_pipe_t*)client;
|
||||
pipe_client = (uv_pipe_t*) client;
|
||||
|
||||
/* Find a connection instance that has been connected, but not yet
|
||||
* accepted. */
|
||||
@@ -925,6 +923,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
server->handle = INVALID_HANDLE_VALUE;
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, server, req, FALSE);
|
||||
}
|
||||
@@ -955,6 +954,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (handle->ipc) {
|
||||
return WSAEINVAL;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_LISTENING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
handle->stream.serv.connection_cb = cb;
|
||||
@@ -1131,6 +1134,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
} else {
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -1148,15 +1152,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (!req->event_handle) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
if (req->wait_handle == INVALID_HANDLE_VALUE) {
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
|
||||
req->event_handle, post_completion_read_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
@@ -1190,8 +1188,16 @@ int uv_pipe_read_start(uv_pipe_t* handle,
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a read
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
uv_pipe_queue_read(loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1326,7 +1332,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
req->coalesced = 0;
|
||||
req->event_handle = NULL;
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & (UV_HANDLE_EMULATE_IOCP | UV_HANDLE_BLOCKING_WRITES)) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
req->write_buffer = uv_null_buf_;
|
||||
|
||||
if (nbufs == 0) {
|
||||
@@ -1375,11 +1390,6 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
handle->write_queue_size += req->u.io.queued_bytes;
|
||||
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
|
||||
/* Using overlapped IO, but wait for completion before returning */
|
||||
req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
|
||||
if (!req->u.io.overlapped.hEvent) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
write_buf.base,
|
||||
write_buf.len,
|
||||
@@ -1388,7 +1398,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
|
||||
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1399,14 +1410,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
/* Request queued by the kernel. */
|
||||
req->u.io.queued_bytes = write_buf.len;
|
||||
handle->write_queue_size += req->u.io.queued_bytes;
|
||||
if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
|
||||
if (WaitForSingleObject(req->event_handle, INFINITE) !=
|
||||
WAIT_OBJECT_0) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
handle->reqs_pending++;
|
||||
@@ -1433,12 +1446,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
|
||||
req->event_handle, post_completion_write_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
Vendored
+64
-123
@@ -134,32 +134,6 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
int result;
|
||||
|
||||
afd_poll_info.Exclusive = TRUE;
|
||||
afd_poll_info.NumberOfHandles = 1;
|
||||
afd_poll_info.Timeout.QuadPart = INT64_MAX;
|
||||
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
|
||||
afd_poll_info.Handles[0].Status = 0;
|
||||
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
|
||||
|
||||
result = uv_msafd_poll(handle->socket,
|
||||
&afd_poll_info,
|
||||
uv__get_afd_poll_info_dummy(),
|
||||
uv__get_overlapped_dummy());
|
||||
|
||||
if (result == SOCKET_ERROR) {
|
||||
DWORD error = WSAGetLastError();
|
||||
if (error != WSA_IO_PENDING)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_req_t* req) {
|
||||
unsigned char mask_events;
|
||||
@@ -226,44 +200,6 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
handle->events = 0;
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return 0;
|
||||
} else {
|
||||
/* Cancel outstanding poll requests by executing another, unique poll
|
||||
* request that forces the outstanding ones to return. */
|
||||
return uv__fast_poll_cancel_poll_req(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
|
||||
WSAPROTOCOL_INFOW* protocol_info) {
|
||||
SOCKET sock = 0;
|
||||
@@ -469,41 +405,6 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events &
|
||||
~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
handle->events = 0;
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
|
||||
}
|
||||
@@ -582,35 +483,43 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
int err;
|
||||
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
int submitted_events;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, events);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, events);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
handle->poll_cb = cb;
|
||||
|
||||
if (handle->events == 0) {
|
||||
uv__handle_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
|
||||
|
||||
if (handle->events & ~submitted_events) {
|
||||
if (handle->flags & UV_HANDLE_POLL_SLOW) {
|
||||
uv__slow_poll_submit_poll_req(handle->loop, handle);
|
||||
} else {
|
||||
uv__fast_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
return uv__poll_set(handle, events, cb);
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_stop(uv_poll_t* handle) {
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, 0);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, 0);
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
return uv__poll_set(handle, 0, handle->poll_cb);
|
||||
}
|
||||
|
||||
|
||||
@@ -624,11 +533,43 @@ void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
|
||||
|
||||
|
||||
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
return uv__fast_poll_close(loop, handle);
|
||||
} else {
|
||||
return uv__slow_poll_close(loop, handle);
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
DWORD error;
|
||||
int result;
|
||||
|
||||
handle->events = 0;
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_POLL_SLOW)
|
||||
return 0;
|
||||
|
||||
/* Cancel outstanding poll requests by executing another, unique poll
|
||||
* request that forces the outstanding ones to return. */
|
||||
afd_poll_info.Exclusive = TRUE;
|
||||
afd_poll_info.NumberOfHandles = 1;
|
||||
afd_poll_info.Timeout.QuadPart = INT64_MAX;
|
||||
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
|
||||
afd_poll_info.Handles[0].Status = 0;
|
||||
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
|
||||
|
||||
result = uv_msafd_poll(handle->socket,
|
||||
&afd_poll_info,
|
||||
uv__get_afd_poll_info_dummy(),
|
||||
uv__get_overlapped_dummy());
|
||||
|
||||
if (result == SOCKET_ERROR) {
|
||||
error = WSAGetLastError();
|
||||
if (error != WSA_IO_PENDING)
|
||||
return uv_translate_sys_error(error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+4
-5
@@ -58,7 +58,6 @@ static const env_var_t required_vars[] = { /* keep me sorted */
|
||||
E_V("USERPROFILE"),
|
||||
E_V("WINDIR"),
|
||||
};
|
||||
static size_t n_required_vars = ARRAY_SIZE(required_vars);
|
||||
|
||||
|
||||
static HANDLE uv_global_job_handle_;
|
||||
@@ -692,7 +691,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
WCHAR* dst_copy;
|
||||
WCHAR** ptr_copy;
|
||||
WCHAR** env_copy;
|
||||
DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
|
||||
DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
|
||||
|
||||
/* first pass: determine size in UTF-16 */
|
||||
for (env = env_block; *env; env++) {
|
||||
@@ -745,7 +744,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
|
||||
|
||||
/* third pass: check for required variables */
|
||||
for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
|
||||
for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
|
||||
int cmp;
|
||||
if (!*ptr_copy) {
|
||||
cmp = -1;
|
||||
@@ -778,10 +777,10 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
|
||||
for (ptr = dst, ptr_copy = env_copy, i = 0;
|
||||
*ptr_copy || i < n_required_vars;
|
||||
*ptr_copy || i < ARRAY_SIZE(required_vars);
|
||||
ptr += len) {
|
||||
int cmp;
|
||||
if (i >= n_required_vars) {
|
||||
if (i >= ARRAY_SIZE(required_vars)) {
|
||||
cmp = 1;
|
||||
} else if (!*ptr_copy) {
|
||||
cmp = -1;
|
||||
|
||||
Vendored
+5
@@ -46,6 +46,11 @@ void uv_signals_init(void) {
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_cleanup(void) {
|
||||
/* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
/* Compare signums first so all watchers with the same signnum end up
|
||||
* adjacent. */
|
||||
|
||||
Vendored
+12
-11
@@ -251,7 +251,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
@@ -268,7 +268,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -428,6 +428,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -466,7 +467,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
closesocket(accept_socket);
|
||||
/* Destroy the event handle */
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
}
|
||||
@@ -509,7 +510,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle);
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -612,8 +613,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
|
||||
: uv_simultaneous_server_accepts;
|
||||
|
||||
if(!handle->tcp.serv.accept_reqs) {
|
||||
handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
|
||||
if (handle->tcp.serv.accept_reqs == NULL) {
|
||||
handle->tcp.serv.accept_reqs =
|
||||
uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
|
||||
if (!handle->tcp.serv.accept_reqs) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
@@ -628,7 +629,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
} else {
|
||||
@@ -737,9 +738,9 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
!handle->read_req.event_handle) {
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
@@ -862,7 +863,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
@@ -1080,7 +1081,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
|
||||
Vendored
+228
-125
@@ -46,14 +46,16 @@
|
||||
|
||||
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
||||
|
||||
#define ANSI_NORMAL 0x00
|
||||
#define ANSI_ESCAPE_SEEN 0x02
|
||||
#define ANSI_CSI 0x04
|
||||
#define ANSI_ST_CONTROL 0x08
|
||||
#define ANSI_IGNORE 0x10
|
||||
#define ANSI_IN_ARG 0x20
|
||||
#define ANSI_IN_STRING 0x40
|
||||
#define ANSI_BACKSLASH_SEEN 0x80
|
||||
#define ANSI_NORMAL 0x0000
|
||||
#define ANSI_ESCAPE_SEEN 0x0002
|
||||
#define ANSI_CSI 0x0004
|
||||
#define ANSI_ST_CONTROL 0x0008
|
||||
#define ANSI_IGNORE 0x0010
|
||||
#define ANSI_IN_ARG 0x0020
|
||||
#define ANSI_IN_STRING 0x0040
|
||||
#define ANSI_BACKSLASH_SEEN 0x0080
|
||||
#define ANSI_EXTENSION 0x0100
|
||||
#define ANSI_DECSCUSR 0x0200
|
||||
|
||||
#define MAX_INPUT_BUFFER_LENGTH 8192
|
||||
#define MAX_CONSOLE_CHAR 8192
|
||||
@@ -62,7 +64,12 @@
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
#define CURSOR_SIZE_SMALL 25
|
||||
#define CURSOR_SIZE_LARGE 100
|
||||
|
||||
static void uv_tty_capture_initial_style(
|
||||
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
|
||||
CONSOLE_CURSOR_INFO* cursor_info);
|
||||
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
static int uv__cancel_read_console(uv_tty_t* handle);
|
||||
|
||||
@@ -149,6 +156,8 @@ static char uv_tty_default_fg_bright = 0;
|
||||
static char uv_tty_default_bg_bright = 0;
|
||||
static char uv_tty_default_inverse = 0;
|
||||
|
||||
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
|
||||
|
||||
/* Determine whether or not ANSI support is enabled. */
|
||||
static BOOL uv__need_check_vterm_state = TRUE;
|
||||
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
|
||||
@@ -183,6 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
DWORD NumberOfEvents;
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
CONSOLE_CURSOR_INFO cursor_info;
|
||||
(void)unused;
|
||||
|
||||
uv__once_init();
|
||||
@@ -215,6 +225,11 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Obtain the cursor info with the output handle. */
|
||||
if (!GetConsoleCursorInfo(handle, &cursor_info)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Obtain the tty_output_lock because the virtual window state is shared
|
||||
* between all uv_tty_t handles. */
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
@@ -222,8 +237,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
if (uv__need_check_vterm_state)
|
||||
uv__determine_vterm_state(handle);
|
||||
|
||||
/* Remember the original console text attributes. */
|
||||
uv_tty_capture_initial_style(&screen_buffer_info);
|
||||
/* Remember the original console text attributes and cursor info. */
|
||||
uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
|
||||
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
@@ -274,7 +289,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
/* Set the default console text attributes based on how the console was
|
||||
* configured when libuv started.
|
||||
*/
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
static void uv_tty_capture_initial_style(
|
||||
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
|
||||
CONSOLE_CURSOR_INFO* cursor_info) {
|
||||
static int style_captured = 0;
|
||||
|
||||
/* Only do this once.
|
||||
@@ -283,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
return;
|
||||
|
||||
/* Save raw win32 attributes. */
|
||||
uv_tty_default_text_attributes = info->wAttributes;
|
||||
uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
|
||||
|
||||
/* Convert black text on black background to use white text. */
|
||||
if (uv_tty_default_text_attributes == 0)
|
||||
@@ -323,6 +340,9 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
|
||||
uv_tty_default_inverse = 1;
|
||||
|
||||
/* Save the cursor size and the cursor state. */
|
||||
uv_tty_default_cursor_info = *cursor_info;
|
||||
|
||||
style_captured = 1;
|
||||
}
|
||||
|
||||
@@ -1230,7 +1250,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
|
||||
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
const COORD origin = {0, 0};
|
||||
const WORD char_attrs = uv_tty_default_text_attributes;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
DWORD count, written;
|
||||
|
||||
if (*error != ERROR_SUCCESS) {
|
||||
@@ -1251,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
|
||||
/* Clear the screen buffer. */
|
||||
retry:
|
||||
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = info.dwSize.X * info.dwSize.Y;
|
||||
count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
|
||||
|
||||
if (!(FillConsoleOutputCharacterW(handle->handle,
|
||||
L'\x20',
|
||||
@@ -1279,7 +1299,13 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
|
||||
/* Move the virtual window up to the top. */
|
||||
uv_tty_virtual_offset = 0;
|
||||
uv_tty_update_virtual_window(&info);
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
/* Reset the cursor size and the cursor state. */
|
||||
if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1618,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
|
||||
CONSOLE_CURSOR_INFO cursor_info;
|
||||
|
||||
if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (style == 0) {
|
||||
cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
|
||||
} else if (style <= 2) {
|
||||
cursor_info.dwSize = CURSOR_SIZE_LARGE;
|
||||
} else {
|
||||
cursor_info.dwSize = CURSOR_SIZE_SMALL;
|
||||
}
|
||||
|
||||
if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
@@ -1645,7 +1696,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
|
||||
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
|
||||
unsigned char previous_eol = handle->tty.wr.previous_eol;
|
||||
unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
|
||||
unsigned short ansi_parser_state = handle->tty.wr.ansi_parser_state;
|
||||
|
||||
/* Store the error here. If we encounter an error, stop trying to do i/o but
|
||||
* keep parsing the buffer so we leave the parser in a consistent state. */
|
||||
@@ -1761,7 +1812,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
case '8':
|
||||
case '8':
|
||||
/* Restore the cursor position and text attributes */
|
||||
FLUSH_TEXT();
|
||||
uv_tty_restore_state(handle, 1, error);
|
||||
@@ -1779,121 +1830,193 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ansi_parser_state == ANSI_IGNORE) {
|
||||
/* We're ignoring this command. Stop only on command character. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if (ansi_parser_state == ANSI_DECSCUSR) {
|
||||
/* So far we've the sequence `ESC [ arg space`, and we're waiting for
|
||||
* the final command byte. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
/* Command byte */
|
||||
if (utf8_codepoint == 'q') {
|
||||
/* Change the cursor shape */
|
||||
int style = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
if (style >= 0 && style <= 6) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_shape(handle, style, error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
}
|
||||
/* Unexpected character, but sequence hasn't ended yet. Ignore the rest
|
||||
* of the sequence. */
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
|
||||
} else if (ansi_parser_state & ANSI_CSI) {
|
||||
if (!(ansi_parser_state & ANSI_IGNORE)) {
|
||||
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
|
||||
/* Parsing a numerical argument */
|
||||
/* So far we've seen `ESC [`, and we may or may not have already parsed
|
||||
* some of the arguments that follow. */
|
||||
|
||||
if (!(ansi_parser_state & ANSI_IN_ARG)) {
|
||||
/* We were not currently parsing a number */
|
||||
|
||||
/* Check for too many arguments */
|
||||
if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
ansi_parser_state |= ANSI_IN_ARG;
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) utf8_codepoint - '0';
|
||||
continue;
|
||||
} else {
|
||||
/* We were already parsing a number. Parse next digit. */
|
||||
uint32_t value = 10 *
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
|
||||
|
||||
/* Check for overflow. */
|
||||
if (value > UINT16_MAX) {
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) value + (utf8_codepoint - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == ';') {
|
||||
/* Denotes the end of an argument. */
|
||||
if (ansi_parser_state & ANSI_IN_ARG) {
|
||||
ansi_parser_state &= ~ANSI_IN_ARG;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* If ANSI_IN_ARG is not set, add another argument and default it
|
||||
* to 0. */
|
||||
|
||||
/* Check for too many arguments */
|
||||
if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
|
||||
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
|
||||
/* Parse a numerical argument. */
|
||||
if (!(ansi_parser_state & ANSI_IN_ARG)) {
|
||||
/* We were not currently parsing a number, add a new one. */
|
||||
/* Check for that there are too many arguments. */
|
||||
if (handle->tty.wr.ansi_csi_argc >=
|
||||
ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
|
||||
handle->tty.wr.ansi_csi_argc == 0) {
|
||||
/* Ignores '?' if it is the first character after CSI[. This is an
|
||||
* extension character from the VT100 codeset that is supported and
|
||||
* used by most ANSI terminals today. */
|
||||
ansi_parser_state |= ANSI_IN_ARG;
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) utf8_codepoint - '0';
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
|
||||
(handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
|
||||
int x, y, d;
|
||||
} else {
|
||||
/* We were already parsing a number. Parse next digit. */
|
||||
uint32_t value = 10 *
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
|
||||
|
||||
/* Command byte */
|
||||
/* Check for overflow. */
|
||||
if (value > UINT16_MAX) {
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) value + (utf8_codepoint - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == ';') {
|
||||
/* Denotes the end of an argument. */
|
||||
if (ansi_parser_state & ANSI_IN_ARG) {
|
||||
ansi_parser_state &= ~ANSI_IN_ARG;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* If ANSI_IN_ARG is not set, add another argument and default
|
||||
* it to 0. */
|
||||
|
||||
/* Check for too many arguments */
|
||||
if (handle->tty.wr.ansi_csi_argc >=
|
||||
|
||||
ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == '?' &&
|
||||
!(ansi_parser_state & ANSI_IN_ARG) &&
|
||||
!(ansi_parser_state & ANSI_EXTENSION) &&
|
||||
handle->tty.wr.ansi_csi_argc == 0) {
|
||||
/* Pass through '?' if it is the first character after CSI */
|
||||
/* This is an extension character from the VT100 codeset */
|
||||
/* that is supported and used by most ANSI terminals today. */
|
||||
ansi_parser_state |= ANSI_EXTENSION;
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint == ' ' &&
|
||||
!(ansi_parser_state & ANSI_EXTENSION)) {
|
||||
/* We expect a command byte to follow after this space. The only
|
||||
* command that we current support is 'set cursor style'. */
|
||||
ansi_parser_state = ANSI_DECSCUSR;
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
/* Command byte */
|
||||
if (ansi_parser_state & ANSI_EXTENSION) {
|
||||
/* Sequence is `ESC [ ? args command`. */
|
||||
switch (utf8_codepoint) {
|
||||
case 'l':
|
||||
/* Hide the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 0, error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* Show the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 1, error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Sequence is `ESC [ args command`. */
|
||||
int x, y, d;
|
||||
switch (utf8_codepoint) {
|
||||
case 'A':
|
||||
/* cursor up */
|
||||
FLUSH_TEXT();
|
||||
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
y = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
/* cursor down */
|
||||
FLUSH_TEXT();
|
||||
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
y = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
/* cursor forward */
|
||||
FLUSH_TEXT();
|
||||
x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
x = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
/* cursor back */
|
||||
FLUSH_TEXT();
|
||||
x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
x = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
/* cursor next line */
|
||||
FLUSH_TEXT();
|
||||
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
y = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
/* cursor previous line */
|
||||
FLUSH_TEXT();
|
||||
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
y = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
/* cursor horizontal move absolute */
|
||||
FLUSH_TEXT();
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0])
|
||||
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
|
||||
uv_tty_move_caret(handle, x, 0, 0, 1, error);
|
||||
break;
|
||||
@@ -1902,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'f':
|
||||
/* cursor move absolute */
|
||||
FLUSH_TEXT();
|
||||
y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
|
||||
y = (handle->tty.wr.ansi_csi_argc >= 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0])
|
||||
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 2 &&
|
||||
handle->tty.wr.ansi_csi_argv[1])
|
||||
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
|
||||
uv_tty_move_caret(handle, x, 0, y, 0, error);
|
||||
break;
|
||||
@@ -1912,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'J':
|
||||
/* Erase screen */
|
||||
FLUSH_TEXT();
|
||||
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
d = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
if (d >= 0 && d <= 2) {
|
||||
uv_tty_clear(handle, d, 1, error);
|
||||
}
|
||||
@@ -1921,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'K':
|
||||
/* Erase line */
|
||||
FLUSH_TEXT();
|
||||
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
d = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
if (d >= 0 && d <= 2) {
|
||||
uv_tty_clear(handle, d, 0, error);
|
||||
}
|
||||
@@ -1944,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
FLUSH_TEXT();
|
||||
uv_tty_restore_state(handle, 0, error);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
/* Hide the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 0, error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* Show the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 1, error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* We don't support commands that use private mode characters or
|
||||
* intermediaries. Ignore the rest of the sequence. */
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* We're ignoring this command. Stop only on command character. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
}
|
||||
/* We don't support commands that use private mode characters or
|
||||
* intermediaries. Ignore the rest of the sequence. */
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+8
-18
@@ -125,17 +125,10 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
int domain;
|
||||
|
||||
/* Use the lower 8 bits for the domain */
|
||||
domain = flags & 0xFF;
|
||||
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & ~0xFF)
|
||||
return UV_EINVAL;
|
||||
|
||||
int uv__udp_init_ex(uv_loop_t* loop,
|
||||
uv_udp_t* handle,
|
||||
unsigned flags,
|
||||
int domain) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
handle->reqs_pending = 0;
|
||||
@@ -174,11 +167,6 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
|
||||
}
|
||||
|
||||
|
||||
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
uv_udp_recv_stop(handle);
|
||||
closesocket(handle->socket);
|
||||
@@ -786,8 +774,10 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
|
||||
mreq.gsr_interface = 0;
|
||||
}
|
||||
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
|
||||
STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = MCAST_JOIN_SOURCE_GROUP;
|
||||
|
||||
Vendored
+148
-56
@@ -60,8 +60,8 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Maximum environment variable size, including the terminating null */
|
||||
#define MAX_ENV_VAR_LENGTH 32767
|
||||
/* A RtlGenRandom() by any other name... */
|
||||
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
@@ -151,20 +151,26 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
|
||||
|
||||
int uv_cwd(char* buffer, size_t* size) {
|
||||
DWORD utf16_len;
|
||||
WCHAR utf16_buffer[MAX_PATH];
|
||||
WCHAR *utf16_buffer;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL || size == NULL) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
|
||||
utf16_len = GetCurrentDirectoryW(0, NULL);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (utf16_len > MAX_PATH) {
|
||||
/* This should be impossible; however the CRT has a code path to deal with
|
||||
* this scenario, so I added a check anyway. */
|
||||
return UV_EIO;
|
||||
}
|
||||
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (utf16_len == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* utf16_len contains the length, *not* including the terminating null. */
|
||||
@@ -188,8 +194,10 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
NULL,
|
||||
NULL);
|
||||
if (r == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (r > (int) *size) {
|
||||
uv__free(utf16_buffer);
|
||||
*size = r;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
@@ -203,6 +211,8 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
*size > INT_MAX ? INT_MAX : (int) *size,
|
||||
NULL,
|
||||
NULL);
|
||||
uv__free(utf16_buffer);
|
||||
|
||||
if (r == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
@@ -213,43 +223,61 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
int uv_chdir(const char* dir) {
|
||||
WCHAR utf16_buffer[MAX_PATH];
|
||||
size_t utf16_len;
|
||||
WCHAR *utf16_buffer;
|
||||
size_t utf16_len, new_utf16_len;
|
||||
WCHAR drive_letter, env_var[4];
|
||||
|
||||
if (dir == NULL) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
utf16_len = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
dir,
|
||||
-1,
|
||||
NULL,
|
||||
0);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
dir,
|
||||
-1,
|
||||
utf16_buffer,
|
||||
MAX_PATH) == 0) {
|
||||
DWORD error = GetLastError();
|
||||
/* The maximum length of the current working directory is 260 chars,
|
||||
* including terminating null. If it doesn't fit, the path name must be too
|
||||
* long. */
|
||||
if (error == ERROR_INSUFFICIENT_BUFFER) {
|
||||
return UV_ENAMETOOLONG;
|
||||
} else {
|
||||
return uv_translate_sys_error(error);
|
||||
}
|
||||
utf16_len) == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
if (!SetCurrentDirectoryW(utf16_buffer)) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Windows stores the drive-local path in an "hidden" environment variable,
|
||||
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
|
||||
* this, so we'll have to do it. */
|
||||
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
|
||||
new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (new_utf16_len > utf16_len ) {
|
||||
uv__free(utf16_buffer);
|
||||
utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
/* When updating the environment variable fails, return UV_OK anyway.
|
||||
* We did successfully change current working directory, only updating
|
||||
* hidden env variable failed. */
|
||||
return 0;
|
||||
}
|
||||
new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
|
||||
}
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (utf16_len > MAX_PATH) {
|
||||
return UV_EIO;
|
||||
uv__free(utf16_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
@@ -281,11 +309,10 @@ int uv_chdir(const char* dir) {
|
||||
env_var[2] = L':';
|
||||
env_var[3] = L'\0';
|
||||
|
||||
if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
SetEnvironmentVariableW(env_var, utf16_buffer);
|
||||
}
|
||||
|
||||
uv__free(utf16_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -358,6 +385,10 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
}
|
||||
|
||||
|
||||
void uv__process_title_cleanup(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int err;
|
||||
int length;
|
||||
@@ -1160,20 +1191,29 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
wchar_t path[MAX_PATH + 2];
|
||||
wchar_t *path;
|
||||
DWORD bufsize;
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
len = GetTempPathW(ARRAY_SIZE(path), path);
|
||||
|
||||
len = 0;
|
||||
len = GetTempPathW(0, NULL);
|
||||
if (len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (len > ARRAY_SIZE(path)) {
|
||||
/* This should not be possible */
|
||||
return UV_EIO;
|
||||
}
|
||||
/* Include space for terminating null char. */
|
||||
len += 1;
|
||||
path = uv__malloc(len * sizeof(wchar_t));
|
||||
if (path == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
len = GetTempPathW(len, path);
|
||||
|
||||
if (len == 0) {
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
@@ -1188,8 +1228,10 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (bufsize == 0) {
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (bufsize > *size) {
|
||||
uv__free(path);
|
||||
*size = bufsize;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
@@ -1203,6 +1245,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
*size,
|
||||
NULL,
|
||||
NULL);
|
||||
uv__free(path);
|
||||
|
||||
if (bufsize == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
@@ -1322,7 +1365,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
HANDLE token;
|
||||
wchar_t username[UNLEN + 1];
|
||||
wchar_t path[MAX_PATH];
|
||||
wchar_t *path;
|
||||
DWORD bufsize;
|
||||
int r;
|
||||
|
||||
@@ -1333,15 +1376,24 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
bufsize = ARRAY_SIZE(path);
|
||||
bufsize = 0;
|
||||
GetUserProfileDirectoryW(token, NULL, &bufsize);
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
r = GetLastError();
|
||||
CloseHandle(token);
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
path = uv__malloc(bufsize * sizeof(wchar_t));
|
||||
if (path == NULL) {
|
||||
CloseHandle(token);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
|
||||
r = GetLastError();
|
||||
CloseHandle(token);
|
||||
|
||||
/* This should not be possible */
|
||||
if (r == ERROR_INSUFFICIENT_BUFFER)
|
||||
return UV_ENOMEM;
|
||||
|
||||
uv__free(path);
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
@@ -1351,6 +1403,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
bufsize = ARRAY_SIZE(username);
|
||||
if (!GetUserNameW(username, &bufsize)) {
|
||||
r = GetLastError();
|
||||
uv__free(path);
|
||||
|
||||
/* This should not be possible */
|
||||
if (r == ERROR_INSUFFICIENT_BUFFER)
|
||||
@@ -1361,6 +1414,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
|
||||
pwd->homedir = NULL;
|
||||
r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
|
||||
uv__free(path);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
@@ -1402,7 +1456,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
|
||||
|
||||
*envitems = uv__calloc(i, sizeof(**envitems));
|
||||
if (envitems == NULL) {
|
||||
if (*envitems == NULL) {
|
||||
FreeEnvironmentStringsW(env);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
@@ -1458,7 +1512,9 @@ fail:
|
||||
|
||||
|
||||
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
wchar_t var[MAX_ENV_VAR_LENGTH];
|
||||
wchar_t fastvar[512];
|
||||
wchar_t* var;
|
||||
DWORD varlen;
|
||||
wchar_t* name_w;
|
||||
DWORD bufsize;
|
||||
size_t len;
|
||||
@@ -1472,25 +1528,52 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
|
||||
var = fastvar;
|
||||
varlen = ARRAY_SIZE(fastvar);
|
||||
|
||||
for (;;) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
len = GetEnvironmentVariableW(name_w, var, varlen);
|
||||
|
||||
if (len < varlen)
|
||||
break;
|
||||
|
||||
/* Try repeatedly because we might have been preempted by another thread
|
||||
* modifying the environment variable just as we're trying to read it.
|
||||
*/
|
||||
if (var != fastvar)
|
||||
uv__free(var);
|
||||
|
||||
varlen = 1 + len;
|
||||
var = uv__malloc(varlen * sizeof(*var));
|
||||
|
||||
if (var == NULL) {
|
||||
r = UV_ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(name_w);
|
||||
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
|
||||
name_w = NULL;
|
||||
|
||||
if (len == 0) {
|
||||
r = GetLastError();
|
||||
if (r != ERROR_SUCCESS)
|
||||
return uv_translate_sys_error(r);
|
||||
if (r != ERROR_SUCCESS) {
|
||||
r = uv_translate_sys_error(r);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check how much space we need */
|
||||
bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (bufsize == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto fail;
|
||||
} else if (bufsize > *size) {
|
||||
*size = bufsize;
|
||||
return UV_ENOBUFS;
|
||||
r = UV_ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
@@ -1503,11 +1586,23 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (bufsize == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
if (bufsize == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*size = bufsize - 1;
|
||||
return 0;
|
||||
r = 0;
|
||||
|
||||
fail:
|
||||
|
||||
if (name_w != NULL)
|
||||
uv__free(name_w);
|
||||
|
||||
if (var != fastvar)
|
||||
uv__free(var);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1862,13 +1957,10 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
}
|
||||
|
||||
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
|
||||
if (pRtlGenRandom == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
if (buflen == 0)
|
||||
return 0;
|
||||
|
||||
if (pRtlGenRandom(buf, buflen) == FALSE)
|
||||
if (SystemFunction036(buf, buflen) == FALSE)
|
||||
return UV_EIO;
|
||||
|
||||
return 0;
|
||||
|
||||
Vendored
-12
@@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Advapi32 function pointers */
|
||||
sRtlGenRandom pRtlGenRandom;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
|
||||
@@ -54,7 +51,6 @@ void uv_winapi_init(void) {
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE advapi32_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@@ -138,12 +134,4 @@ void uv_winapi_init(void) {
|
||||
pSetWinEventHook = (sSetWinEventHook)
|
||||
GetProcAddress(user32_module, "SetWinEventHook");
|
||||
}
|
||||
|
||||
advapi32_module = GetModuleHandleA("advapi32.dll");
|
||||
if (advapi32_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
pRtlGenRandom =
|
||||
(sRtlGenRandom) GetProcAddress(advapi32_module, "SystemFunction036");
|
||||
}
|
||||
|
||||
Vendored
+7
-8
@@ -4152,6 +4152,10 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
struct {
|
||||
ULONG StringCount;
|
||||
WCHAR StringList[1];
|
||||
} AppExecLinkReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
#endif
|
||||
@@ -4517,6 +4521,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_APPEXECLINK
|
||||
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
|
||||
#endif
|
||||
|
||||
typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||
(PVOID ApcContext,
|
||||
@@ -4589,11 +4596,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
|
||||
ULONG Length,
|
||||
PULONG ReturnLength);
|
||||
|
||||
/*
|
||||
* Advapi32 headers
|
||||
*/
|
||||
typedef BOOLEAN (WINAPI *sRtlGenRandom)(PVOID Buffer, ULONG BufferLength);
|
||||
|
||||
/*
|
||||
* Kernel32 headers
|
||||
*/
|
||||
@@ -4736,9 +4738,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
extern sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Advapi32 function pointers */
|
||||
extern sRtlGenRandom pRtlGenRandom;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user