Beispiel #1
0
/// 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
/// 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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
    }
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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.
}
Beispiel #13
0
bool os_isatty(int fd)
{
    return uv_guess_handle(fd) == UV_TTY;
}
Beispiel #14
0
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;
}
Beispiel #15
0
extern "C" int
rust_uv_guess_handle(int fd) {
    return uv_guess_handle(fd);
}
Beispiel #16
0
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;
}
Beispiel #17
0
/* 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);
}
Beispiel #18
0
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;
}
Beispiel #19
0
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;
}