/// Check what `name` is: /// @return NODE_NORMAL: file or directory (or doesn't exist) /// NODE_WRITABLE: writable device, socket, fifo, etc. /// NODE_OTHER: non-writable things int os_nodetype(const char *name) { #ifdef WIN32 // 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; if (0 != os_stat(name, &statbuf)) { return NODE_NORMAL; // File doesn't exist. } #ifndef WIN32 // libuv does not handle BLK and DIR in uv_handle_type. // Related: https://github.com/joyent/libuv/pull/1421 if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) { return NODE_NORMAL; } if (S_ISBLK(statbuf.st_mode)) { // block device isn't writable return NODE_OTHER; } #endif // Vim os_win32.c:mch_nodetype does this (since patch 7.4.015): // if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { // wn = enc_to_utf16(name, NULL); // hFile = CreatFile(wn, ...) // to get a HANDLE. But libuv just calls win32's _get_osfhandle() on the fd we // give it. uv_fs_open calls fs__capture_path which does a similar dance and // saves us the hassle. int nodetype = NODE_WRITABLE; int fd = os_open(name, O_RDONLY, 0); switch(uv_guess_handle(fd)) { case UV_TTY: // FILE_TYPE_CHAR nodetype = NODE_WRITABLE; break; case UV_FILE: // FILE_TYPE_DISK nodetype = NODE_NORMAL; break; 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: default: #ifdef WIN32 nodetype = NODE_NORMAL; #else nodetype = NODE_WRITABLE; // Everything else is writable? #endif break; } close(fd); return nodetype; }
void *init_stdio_handle(uv_file fd,int readable) { void *handle; uv_handle_type type = uv_guess_handle(fd); switch(type) { case UV_TTY: handle = malloc(sizeof(uv_tty_t)); uv_tty_init(jl_io_loop,(uv_tty_t*)handle,fd,readable); ((uv_tty_t*)handle)->data=0; uv_tty_set_mode((void*)handle,0); //cooked stdio break; case UV_NAMED_PIPE: case UV_FILE: handle = malloc(sizeof(uv_pipe_t)); uv_pipe_init(jl_io_loop, (uv_pipe_t*)handle,(readable?UV_PIPE_READABLE:UV_PIPE_WRITEABLE)); uv_pipe_open((uv_pipe_t*)handle,fd); ((uv_pipe_t*)handle)->data=0; break; case UV_TCP: case UV_UDP: default: handle=NULL; jl_errorf("This type of handle for stdio is not yet supported (%d)!\n",type); break; } return handle; }
int main(int argc, char *argv[]) { if (argc < 2) return -1; int r = uv_pipe_init(uv_default_loop(), &stdin_pipe, 0); assert(r==0); uv_pipe_open(&stdin_pipe, 0); uv_pipe_init(uv_default_loop(), &stdout_pipe, 0); uv_pipe_open(&stdin_pipe, 1); printf("%d\n", uv_guess_handle(0)); uv_fs_t file_req; int fd = uv_fs_open(uv_default_loop(), &file_req, argv[1], O_WRONLY | O_CREAT, 0644, NULL); uv_pipe_init(uv_default_loop(), &file_pipe, 0); uv_pipe_open(&file_pipe, fd); printf("hhhhhhhhhh\n"); uv_read_start((uv_stream_t*) &stdin_pipe, buf_alloc, OnRead); uv_run(uv_default_loop(), UV_RUN_DEFAULT); return 0; }
void rstream_set_file(RStream *rstream, uv_file file) { rstream->file_type = uv_guess_handle(file); if (rstream->free_handle) { // If this is the second time we're calling this function, free the // previously allocated memory if (rstream->fread_idle != NULL) { uv_close((uv_handle_t *)rstream->fread_idle, close_cb); } else { uv_close((uv_handle_t *)rstream->stream, close_cb); } } if (rstream->file_type == UV_FILE) { // Non-blocking file reads are simulated with a idle handle that reads // in chunks of rstream->buffer_size, giving time for other events to // be processed between reads. rstream->fread_idle = xmalloc(sizeof(uv_idle_t)); uv_idle_init(uv_default_loop(), rstream->fread_idle); rstream->fread_idle->data = rstream; } else { // Only pipes are supported for now assert(rstream->file_type == UV_NAMED_PIPE || rstream->file_type == UV_TTY); rstream->stream = xmalloc(sizeof(uv_pipe_t)); uv_pipe_init(uv_default_loop(), (uv_pipe_t *)rstream->stream, 0); uv_pipe_open((uv_pipe_t *)rstream->stream, file); rstream->stream->data = rstream; } rstream->fd = file; rstream->free_handle = true; }
static int couv_handle_guess(lua_State *L) { uv_file file; uv_handle_type type; file = luaL_checkint(L, 1); type = uv_guess_handle(file); lua_pushnumber(L, type); return 1; }
static int luv_guess_handle(lua_State* L) { uv_file file = luaL_checkinteger(L, 1); switch (uv_guess_handle(file)) { #define XX(uc, lc) case UV_##uc: lua_pushstring(L, #lc); break; UV_HANDLE_TYPE_MAP(XX) #undef XX case UV_FILE: lua_pushstring(L, "file"); break; default: return 0; } return 1; }
/// Sets the underlying file descriptor that will be written to. Only pipes /// are supported for now. /// /// @param wstream The `WStream` instance /// @param file The file descriptor void wstream_set_file(WStream *wstream, uv_file file) { uv_handle_type type = uv_guess_handle(file); assert(type == UV_NAMED_PIPE || type == UV_TTY); wstream->stream = xmalloc(sizeof(uv_pipe_t)); uv_pipe_init(uv_default_loop(), (uv_pipe_t *)wstream->stream, 0); uv_pipe_open((uv_pipe_t *)wstream->stream, file); wstream->stream->data = NULL; handle_set_wstream((uv_handle_t *)wstream->stream, wstream); wstream->free_handle = true; }
static void read_cb(RStream *rstream, void *data, bool at_eof) { if (at_eof) { if (!started_reading && rstream_is_regular_file(rstream) && uv_guess_handle(2) == UV_TTY) { // Read error. Since stderr is a tty we switch to reading from it. This // is for handling for cases like "foo | xargs vim" because xargs // redirects stdin from /dev/null. Previously, this was done in ui.c stderr_switch(); } else { eof = true; } } started_reading = true; }
static PyObject * TTY_func_isatty(PyObject *cls, PyObject *args) { int fd; UNUSED_ARG(cls); if (!PyArg_ParseTuple(args, "i:isatty", &fd)) { return NULL; } if (uv_guess_handle(fd) == UV_TTY) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } }
void *init_stdio_handle(uv_file fd,int readable) { void *handle; uv_handle_type type = uv_guess_handle(fd); //printf("%d: %d -- %d\n", fd, type); switch(type) { case UV_TTY: handle = malloc(sizeof(uv_tty_t)); if (uv_tty_init(jl_io_loop,(uv_tty_t*)handle,fd,readable)) { jl_errorf("Error initializing stdio in uv_tty_init (%d, %d)\n", fd, type); abort(); } ((uv_tty_t*)handle)->data=0; uv_tty_set_mode((void*)handle,0); //cooked stdio break; case UV_FILE: #ifdef _WIN32 jl_errorf("This type of handle for stdio is not yet supported on Windows (%d, %d)!\n", fd, type); handle = NULL; break; #endif case UV_NAMED_PIPE: handle = malloc(sizeof(uv_pipe_t)); if (uv_pipe_init(jl_io_loop, (uv_pipe_t*)handle, (readable?UV_PIPE_READABLE:UV_PIPE_WRITEABLE))) { jl_errorf("Error initializing stdio in uv_pipe_init (%d, %d)\n", fd, type); abort(); } if (uv_pipe_open((uv_pipe_t*)handle,fd)) { jl_errorf("Error initializing stdio in uv_pipe_open (%d, %d)\n", fd, type); abort(); } ((uv_pipe_t*)handle)->data=0; break; case UV_TCP: case UV_UDP: default: jl_errorf("This type of handle for stdio is not yet supported (%d, %d)!\n", fd, type); handle = NULL; break; } return handle; }
void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream, void *data) { stream->uvstream = uvstream; if (fd >= 0) { uv_handle_type type = uv_guess_handle(fd); stream->fd = fd; if (type == UV_FILE) { // Non-blocking file reads are simulated with an idle handle that reads in // chunks of the ring buffer size, giving time for other events to be // processed between reads. uv_idle_init(&loop->uv, &stream->uv.idle); stream->uv.idle.data = stream; } else { assert(type == UV_NAMED_PIPE || type == UV_TTY); uv_pipe_init(&loop->uv, &stream->uv.pipe, 0); uv_pipe_open(&stream->uv.pipe, fd); stream->uvstream = (uv_stream_t *)&stream->uv.pipe; } } if (stream->uvstream) { stream->uvstream->data = stream; } stream->data = data; stream->internal_data = NULL; stream->fpos = 0; stream->curmem = 0; stream->maxmem = 0; stream->pending_reqs = 0; stream->read_cb = NULL; stream->write_cb = NULL; stream->close_cb = NULL; stream->internal_close_cb = NULL; stream->closed = false; stream->buffer = NULL; }
void stdinReadStart(WrenVM* vm) { if (stdinStream == NULL) { if (uv_guess_handle(stdinDescriptor) == UV_TTY) { // stdin is connected to a terminal. uv_tty_t* handle = (uv_tty_t*)malloc(sizeof(uv_tty_t)); uv_tty_init(getLoop(), handle, stdinDescriptor, true); stdinStream = (uv_stream_t*)handle; } else { // stdin is a pipe or a file. uv_pipe_t* handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t)); uv_pipe_init(getLoop(), handle, false); uv_pipe_open(handle, stdinDescriptor); stdinStream = (uv_stream_t*)handle; } } uv_read_start(stdinStream, allocCallback, stdinReadCallback); // TODO: Check return. }
bool os_isatty(int fd) { return uv_guess_handle(fd) == UV_TTY; }
static int stdio_over_pipes_helper() { /* Write several buffers to test that the write order is preserved. */ char* buffers[] = { "he", "ll", "o ", "wo", "rl", "d", "\n" }; uv_write_t write_req[ARRAY_SIZE(buffers)]; uv_buf_t buf[ARRAY_SIZE(buffers)]; int r, i; uv_loop_t* loop = uv_default_loop(); ASSERT(UV_NAMED_PIPE == uv_guess_handle(0)); ASSERT(UV_NAMED_PIPE == uv_guess_handle(1)); r = uv_pipe_init(loop, &stdin_pipe, 0); ASSERT(r == 0); r = uv_pipe_init(loop, &stdout_pipe, 0); ASSERT(r == 0); uv_pipe_open(&stdin_pipe, 0); uv_pipe_open(&stdout_pipe, 1); /* Unref both stdio handles to make sure that all writes complete. */ uv_unref(loop); uv_unref(loop); for (i = 0; i < ARRAY_SIZE(buffers); i++) { buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); } for (i = 0; i < ARRAY_SIZE(buffers); i++) { r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1, after_pipe_write); ASSERT(r == 0); } uv_run(loop); ASSERT(after_write_called == 7); ASSERT(on_pipe_read_called == 0); ASSERT(close_cb_called == 0); uv_ref(loop); uv_ref(loop); r = uv_read_start((uv_stream_t*)&stdin_pipe, on_pipe_read_alloc, on_pipe_read); ASSERT(r == 0); uv_run(loop); ASSERT(after_write_called == 7); ASSERT(on_pipe_read_called == 1); ASSERT(close_cb_called == 2); return 0; }
extern "C" int rust_uv_guess_handle(int fd) { return uv_guess_handle(fd); }
int luv_handle_type(lua_State* L) { uv_file file = luaL_checkint(L, 1); uv_handle_type type = uv_guess_handle(file); lua_pushstring(L, luv_handle_type_to_string(type)); return 1; }
/* Checks if the file is a TTY. */ static MVMint64 is_tty(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; return (uv_guess_handle(data->fd) == UV_TTY); }
void *init_stdio_handle(uv_file fd,int readable) { void *handle; uv_handle_type type = uv_guess_handle(fd); jl_uv_file_t *file; #ifndef _OS_WINDOWS_ // Duplicate the file descritor so we can later dup it over if we want to redirect // STDIO without having to worry about closing the associated libuv object. // On windows however, libuv objects remember streams by their HANDLE, so this is // unnessecary. fd = dup(fd); #endif //printf("%d: %d -- %d\n", fd, type); switch(type) { case UV_TTY: handle = malloc(sizeof(uv_tty_t)); if (uv_tty_init(jl_io_loop,(uv_tty_t*)handle,fd,readable)) { jl_errorf("Error initializing stdio in uv_tty_init (%d, %d)\n", fd, type); abort(); } ((uv_tty_t*)handle)->data=0; uv_tty_set_mode((void*)handle,0); //cooked stdio break; case UV_FILE: file = malloc(sizeof(jl_uv_file_t)); file->loop = jl_io_loop; file->type = UV_FILE; file->file = fd; file->data = 0; handle = file; break; case UV_NAMED_PIPE: handle = malloc(sizeof(uv_pipe_t)); if (uv_pipe_init(jl_io_loop, (uv_pipe_t*)handle, (readable?UV_PIPE_READABLE:UV_PIPE_WRITABLE))) { jl_errorf("Error initializing stdio in uv_pipe_init (%d, %d)\n", fd, type); abort(); } if (uv_pipe_open((uv_pipe_t*)handle,fd)) { jl_errorf("Error initializing stdio in uv_pipe_open (%d, %d)\n", fd, type); abort(); } ((uv_pipe_t*)handle)->data=0; break; case UV_TCP: handle = malloc(sizeof(uv_tcp_t)); if (uv_tcp_init(jl_io_loop, (uv_tcp_t*)handle)) { jl_errorf("Error initializing stdio in uv_tcp_init (%d, %d)\n", fd, type); abort(); } if (uv_tcp_open((uv_tcp_t*)handle,fd)) { jl_errorf("Error initializing stdio in uv_tcp_open (%d, %d)\n", fd, type); abort(); } ((uv_tcp_t*)handle)->data=0; break; case UV_UDP: default: jl_errorf("This type of handle for stdio is not yet supported (%d, %d)!\n", fd, type); handle = NULL; break; } return handle; }
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv_handle_type type; int flags; int newfd; int r; int saved_flags; char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random * (but obviously not /dev/tty.) */ type = uv_guess_handle(fd); if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) return UV_EINVAL; flags = 0; newfd = -1; /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it * with us. * * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also * affects fd 1 of `cat` because both file descriptors refer to the same * struct file in the kernel. When we reopen our fd 0, it points to a * different struct file, hence changing its properties doesn't affect * other processes. */ if (type == UV_TTY) { /* Reopening a pty in master mode won't work either because the reopened * pty will be in slave mode (*BSD) or reopening will allocate a new * master/slave pair (Linux). Therefore check if the fd points to a * slave device. */ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) r = uv__open_cloexec(path, O_RDWR); else r = -1; if (r < 0) { /* fallback to using blocking writes */ if (!readable) flags |= UV_HANDLE_BLOCKING_WRITES; goto skip; } newfd = r; r = uv__dup2_cloexec(newfd, fd); if (r < 0 && r != UV_EINVAL) { /* EINVAL means newfd == fd which could conceivably happen if another * thread called close(fd) between our calls to isatty() and open(). * That's a rather unlikely event but let's handle it anyway. */ uv__close(newfd); return r; } fd = newfd; } #if defined(__APPLE__) /* Save the fd flags in case we need to restore them due to an error. */ do saved_flags = fcntl(fd, F_GETFL); while (saved_flags == -1 && errno == EINTR); if (saved_flags == -1) { if (newfd != -1) uv__close(newfd); return UV__ERR(errno); } #endif /* Pacify the compiler. */ (void) &saved_flags; skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); /* If anything fails beyond this point we need to remove the handle from * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ if (!(flags & UV_HANDLE_BLOCKING_WRITES)) uv__nonblock(fd, 1); #if defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { int rc = r; if (newfd != -1) uv__close(newfd); QUEUE_REMOVE(&tty->handle_queue); do r = fcntl(fd, F_SETFL, saved_flags); while (r == -1 && errno == EINTR); return rc; } #endif if (readable) flags |= UV_HANDLE_READABLE; else flags |= UV_HANDLE_WRITABLE; uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; return 0; }