unix: support long path names in pipe.c (#5047)
Continues: #4676 Fixes: #2826
This commit is contained in:
parent
048acb509c
commit
919b92d944
@ -29,6 +29,18 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
union uv__sockaddr_un {
|
||||
struct sockaddr sa;
|
||||
struct uv__sockaddr_un_path {
|
||||
char pad[offsetof(struct sockaddr_un, sun_path)];
|
||||
#ifdef SOCK_MAXADDRLEN
|
||||
char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path)];
|
||||
#else
|
||||
char path[sizeof(((struct sockaddr_un*)0)->sun_path)];
|
||||
#endif
|
||||
} up;
|
||||
};
|
||||
|
||||
|
||||
/* Does the file path contain embedded nul bytes? */
|
||||
static int includes_invalid_nul(const char *s, size_t n) {
|
||||
@ -64,7 +76,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
const char* name,
|
||||
size_t namelen,
|
||||
unsigned int flags) {
|
||||
struct sockaddr_un saddr;
|
||||
union uv__sockaddr_un saddr;
|
||||
char* pipe_fname;
|
||||
int sockfd;
|
||||
int err;
|
||||
@ -90,12 +102,12 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
if (namelen > sizeof(saddr.up.path))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Truncate long paths. Documented behavior. */
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
namelen = sizeof(saddr.sun_path);
|
||||
if (namelen > sizeof(saddr.up.path))
|
||||
namelen = sizeof(saddr.up.path);
|
||||
|
||||
/* Already bound? */
|
||||
if (uv__stream_fd(handle) >= 0)
|
||||
@ -125,10 +137,10 @@ int uv_pipe_bind2(uv_pipe_t* handle,
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
memcpy(&saddr.sun_path, name, namelen);
|
||||
saddr.sun_family = AF_UNIX;
|
||||
memcpy(saddr.up.path, name, namelen);
|
||||
saddr.sa.sa_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) {
|
||||
if (bind(sockfd, &saddr.sa, addrlen)) {
|
||||
err = UV__ERR(errno);
|
||||
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
||||
if (err == UV_ENOENT)
|
||||
@ -257,7 +269,7 @@ int uv_pipe_connect2(uv_connect_t* req,
|
||||
size_t namelen,
|
||||
unsigned int flags,
|
||||
uv_connect_cb cb) {
|
||||
struct sockaddr_un saddr;
|
||||
union uv__sockaddr_un saddr;
|
||||
int new_sock;
|
||||
int err;
|
||||
int r;
|
||||
@ -276,12 +288,12 @@ int uv_pipe_connect2(uv_connect_t* req,
|
||||
return UV_EINVAL;
|
||||
|
||||
if (flags & UV_PIPE_NO_TRUNCATE)
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
if (namelen > sizeof(saddr.up.path))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Truncate long paths. Documented behavior. */
|
||||
if (namelen > sizeof(saddr.sun_path))
|
||||
namelen = sizeof(saddr.sun_path);
|
||||
if (namelen > sizeof(saddr.up.path))
|
||||
namelen = sizeof(saddr.up.path);
|
||||
|
||||
new_sock = (uv__stream_fd(handle) == -1);
|
||||
|
||||
@ -293,8 +305,8 @@ int uv_pipe_connect2(uv_connect_t* req,
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
memcpy(&saddr.sun_path, name, namelen);
|
||||
saddr.sun_family = AF_UNIX;
|
||||
memcpy(saddr.up.path, name, namelen);
|
||||
saddr.sa.sa_family = AF_UNIX;
|
||||
|
||||
if (*name == '\0')
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
|
||||
@ -355,7 +367,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
#else
|
||||
static const int is_linux = 0;
|
||||
#endif
|
||||
struct sockaddr_un sa;
|
||||
union uv__sockaddr_un sa;
|
||||
socklen_t addrlen;
|
||||
size_t slop;
|
||||
char* p;
|
||||
@ -376,15 +388,15 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
}
|
||||
|
||||
slop = 1;
|
||||
if (is_linux && sa.sun_path[0] == '\0') {
|
||||
if (is_linux && sa.up.path[0] == '\0') {
|
||||
/* Linux abstract namespace. Not zero-terminated. */
|
||||
slop = 0;
|
||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||
} else {
|
||||
p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path));
|
||||
p = memchr(sa.up.path, '\0', sizeof(sa.up.path));
|
||||
if (p == NULL)
|
||||
p = ARRAY_END(sa.sun_path);
|
||||
addrlen = p - sa.sun_path;
|
||||
p = ARRAY_END(sa.up.path);
|
||||
addrlen = p - sa.up.path;
|
||||
}
|
||||
|
||||
if ((size_t)addrlen + slop > *size) {
|
||||
@ -392,7 +404,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, sa.sun_path, addrlen);
|
||||
memcpy(buffer, sa.up.path, addrlen);
|
||||
*size = addrlen;
|
||||
|
||||
/* only null-terminate if it's not an abstract socket */
|
||||
|
||||
@ -219,6 +219,7 @@ TEST_DECLARE (pipe_getsockname)
|
||||
TEST_DECLARE (pipe_getsockname_abstract)
|
||||
TEST_DECLARE (pipe_getsockname_autobind)
|
||||
TEST_DECLARE (pipe_getsockname_blocking)
|
||||
TEST_DECLARE (pipe_getsockname_long_path)
|
||||
TEST_DECLARE (pipe_pending_instances)
|
||||
TEST_DECLARE (pipe_sendmsg)
|
||||
TEST_DECLARE (pipe_server_close)
|
||||
@ -856,6 +857,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (pipe_getsockname_abstract)
|
||||
TEST_ENTRY (pipe_getsockname_autobind)
|
||||
TEST_ENTRY (pipe_getsockname_blocking)
|
||||
TEST_ENTRY (pipe_getsockname_long_path)
|
||||
TEST_ENTRY (pipe_pending_instances)
|
||||
TEST_ENTRY (pipe_sendmsg)
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# include <unistd.h> /* close */
|
||||
#else
|
||||
# include <fcntl.h>
|
||||
@ -368,3 +370,52 @@ TEST_IMPL(pipe_getsockname_blocking) {
|
||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void long_path_connect_cb(uv_connect_t* req, int status) {
|
||||
ASSERT_OK(status);
|
||||
uv_close((uv_handle_t*) req->handle, NULL);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(pipe_getsockname_long_path) {
|
||||
#ifndef SOCK_MAXADDRLEN
|
||||
RETURN_SKIP("long unix paths not supported on this platform");
|
||||
#else
|
||||
uv_loop_t* loop;
|
||||
size_t len;
|
||||
int r;
|
||||
char path[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1];
|
||||
char name[SOCK_MAXADDRLEN - offsetof(struct sockaddr_un, sun_path) + 1];
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT_NOT_NULL(loop);
|
||||
|
||||
r = uv_pipe_init(loop, &pipe_server, 0);
|
||||
ASSERT_OK(r);
|
||||
r = uv_pipe_init(loop, &pipe_client, 0);
|
||||
ASSERT_OK(r);
|
||||
|
||||
memset(path, 'x', sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
|
||||
r = uv_pipe_bind(&pipe_server, path);
|
||||
ASSERT_OK(r);
|
||||
|
||||
len = sizeof(name);
|
||||
r = uv_pipe_getsockname(&pipe_server, name, &len);
|
||||
|
||||
ASSERT_OK(r);
|
||||
ASSERT_EQ(len, strlen(path));
|
||||
ASSERT_MEM_EQ(path, name, len);
|
||||
|
||||
r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
|
||||
ASSERT_OK(r);
|
||||
|
||||
uv_pipe_connect(&connect_req, &pipe_client, path, long_path_connect_cb);
|
||||
uv_close((uv_handle_t*) &pipe_server, NULL);
|
||||
ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
|
||||
|
||||
MAKE_VALGRIND_HAPPY(loop);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user