Merge #7561 'os_open: UV_EINVAL on NULL filename'

This commit is contained in:
Justin M. Keyes 2017-11-18 01:01:25 +01:00 committed by GitHub
commit f185c739bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -133,22 +133,12 @@ bool os_isdir(const char_u *name)
int os_nodetype(const char *name) int os_nodetype(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
#ifdef WIN32 #ifndef WIN32 // Unix
// Edge case from Vim os_win32.c:
// We can't open a file with a name "\\.\con" or "\\.\prn", trying to read
// from it later will cause Vim to hang. Thus return NODE_WRITABLE here.
if (STRNCMP(name, "\\\\.\\", 4) == 0) {
return NODE_WRITABLE;
}
#endif
uv_stat_t statbuf; uv_stat_t statbuf;
if (0 != os_stat(name, &statbuf)) { if (0 != os_stat(name, &statbuf)) {
return NODE_NORMAL; // File doesn't exist. return NODE_NORMAL; // File doesn't exist.
} }
// uv_handle_type does not distinguish BLK and DIR.
#ifndef WIN32
// libuv does not handle BLK and DIR in uv_handle_type.
// Related: https://github.com/joyent/libuv/pull/1421 // Related: https://github.com/joyent/libuv/pull/1421
if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) { if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) {
return NODE_NORMAL; return NODE_NORMAL;
@ -156,48 +146,51 @@ int os_nodetype(const char *name)
if (S_ISBLK(statbuf.st_mode)) { // block device isn't writable if (S_ISBLK(statbuf.st_mode)) { // block device isn't writable
return NODE_OTHER; return NODE_OTHER;
} }
#endif // Everything else is writable?
// buf_write() expects NODE_WRITABLE for char device /dev/stderr.
// Vim os_win32.c:mch_nodetype does this (since patch 7.4.015): return NODE_WRITABLE;
// if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { #else // Windows
// wn = enc_to_utf16(name, NULL); // Edge case from Vim os_win32.c:
// hFile = CreatFile(wn, ...) // We can't open a file with a name "\\.\con" or "\\.\prn", trying to read
// to get a HANDLE. But libuv just calls win32's _get_osfhandle() on the fd we // from it later will cause Vim to hang. Thus return NODE_WRITABLE here.
// give it. uv_fs_open calls fs__capture_path which does a similar dance and if (STRNCMP(name, "\\\\.\\", 4) == 0) {
// saves us the hassle. return NODE_WRITABLE;
int nodetype = NODE_WRITABLE;
int fd = os_open(name, O_RDONLY
#ifdef O_NONBLOCK
| O_NONBLOCK
#endif
, 0);
if (fd == -1) {
return NODE_OTHER; // open() failed.
} }
switch (uv_guess_handle(fd)) { // Vim os_win32.c:mch_nodetype does (since 7.4.015):
case UV_TTY: // FILE_TYPE_CHAR // wn = enc_to_utf16(name, NULL);
nodetype = NODE_WRITABLE; // hFile = CreatFile(wn, ...)
break; // to get a HANDLE. Whereas libuv just calls _get_osfhandle() on the fd we
case UV_FILE: // FILE_TYPE_DISK // give it. But uv_fs_open later calls fs__capture_path which does a similar
nodetype = NODE_NORMAL; // utf8-to-utf16 dance and saves us the hassle.
break;
case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c // macOS: os_open(/dev/stderr) would return UV_EACCES.
case UV_UDP: // unix only int fd = os_open(name, O_RDONLY
case UV_TCP: // unix only # ifdef O_NONBLOCK
| O_NONBLOCK
# endif
, 0);
if (fd < 0) { // open() failed.
return NODE_NORMAL;
}
int guess = uv_guess_handle(fd);
if (close(fd) == -1) {
ELOG("close(%d) failed. name='%s'", fd, name);
}
switch (guess) {
case UV_TTY: // FILE_TYPE_CHAR
return NODE_WRITABLE;
case UV_FILE: // FILE_TYPE_DISK
return NODE_NORMAL;
case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c
case UV_UDP: // unix only
case UV_TCP: // unix only
case UV_UNKNOWN_HANDLE: case UV_UNKNOWN_HANDLE:
default: default:
#ifdef WIN32 return NODE_OTHER; // Vim os_win32.c default
nodetype = NODE_NORMAL;
#else
nodetype = NODE_WRITABLE; // Everything else is writable?
#endif
break;
} }
#endif
close(fd);
return nodetype;
} }
/// Gets the absolute path of the currently running executable. /// Gets the absolute path of the currently running executable.
@ -394,9 +387,11 @@ end:
/// @param mode Permissions for the newly-created file (IGNORED if 'flags' is /// @param mode Permissions for the newly-created file (IGNORED if 'flags' is
/// not `O_CREAT` or `O_TMPFILE`), subject to the current umask /// not `O_CREAT` or `O_TMPFILE`), subject to the current umask
/// @return file descriptor, or libuv error code on failure /// @return file descriptor, or libuv error code on failure
int os_open(const char* path, int flags, int mode) int os_open(const char *path, int flags, int mode)
FUNC_ATTR_NONNULL_ALL
{ {
if (path == NULL) { // uv_fs_open asserts on NULL. #7561
return UV_EINVAL;
}
int r; int r;
RUN_UV_FS_FUNC(r, uv_fs_open, path, flags, mode, NULL); RUN_UV_FS_FUNC(r, uv_fs_open, path, flags, mode, NULL);
return r; return r;
@ -603,12 +598,12 @@ int os_fsync(int fd)
/// Get stat information for a file. /// Get stat information for a file.
/// ///
/// @return libuv return code. /// @return libuv return code, or -errno
static int os_stat(const char *name, uv_stat_t *statbuf) static int os_stat(const char *name, uv_stat_t *statbuf)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(2)
{ {
if (!name) { if (!name) {
return UV_ENOENT; return UV_EINVAL;
} }
uv_fs_t request; uv_fs_t request;
int result = uv_fs_stat(&fs_loop, &request, name, NULL); int result = uv_fs_stat(&fs_loop, &request, name, NULL);
@ -1078,7 +1073,8 @@ shortcut_end:
#endif #endif
int os_translate_sys_error(int sys_errno) { int os_translate_sys_error(int sys_errno)
{
#ifdef HAVE_UV_TRANSLATE_SYS_ERROR #ifdef HAVE_UV_TRANSLATE_SYS_ERROR
return uv_translate_sys_error(sys_errno); return uv_translate_sys_error(sys_errno);
#elif defined(WIN32) #elif defined(WIN32)