Example #1
0
/*
 * Arguments: path (string), [permissions (number)]
 * Returns: [boolean]
 */
static int
sys_mkdir (lua_State *L)
{
  const char *path = luaL_checkstring(L, 1);
  int res;

#ifndef _WIN32
  mode_t perm = (mode_t) lua_tointeger(L, 2);

  sys_vm_leave(L);
  res = mkdir(path, perm);
  sys_vm_enter(L);
#else
  {
    void *os_path = utf8_to_filename(path);
    if (!os_path)
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

    sys_vm_leave(L);
    res = is_WinNT
     ? !CreateDirectoryW(os_path, NULL)
     : !CreateDirectoryA(os_path, NULL);

    free(os_path);
    sys_vm_enter(L);
  }
#endif
  if (!res) {
    lua_pushboolean(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}
Example #2
0
/*
 * Arguments: path (string)
 * Returns: [boolean]
 */
static int
sys_rmdir (lua_State *L)
{
  const char *path = luaL_checkstring(L, 1);
  int res;

#ifndef _WIN32
  sys_vm_leave(L);
  res = rmdir(path);
  sys_vm_enter(L);
#else
  {
    void *os_path = utf8_to_filename(path);
    if (!os_path)
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

    sys_vm_leave(L);
    res = is_WinNT
     ? !RemoveDirectoryW(os_path)
     : !RemoveDirectoryA(os_path);

    free(os_path);
    sys_vm_enter(L);
  }
#endif
  if (!res) {
    lua_pushboolean(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}
Example #3
0
/*
 * Arguments: milliseconds (number), [don't interrupt (boolean)]
 */
static int
thread_sleep (lua_State *L)
{
    const int msec = lua_tointeger(L, 1);
#ifndef _WIN32
    const int not_intr = lua_toboolean(L, 2);
#endif

    sys_vm_leave();
#ifndef _WIN32
    {
	struct timespec req;
	struct timespec *rem = not_intr ? &req : NULL;
	int res;

	req.tv_sec = msec / 1000;
	req.tv_nsec = (msec % 1000) * 1000000;

	do res = nanosleep(&req, rem);
	while (res == -1 && SYS_ERRNO == EINTR && not_intr);
    }
#else
    Sleep(msec);
#endif
    sys_vm_enter();
    return 0;
}
Example #4
0
/*
 * Arguments: path (string)
 * Returns: [total_bytes (number), available_bytes (number),
 *	free_bytes (number)]
 */
static int
sys_statfs (lua_State *L)
{
  const char *path = luaL_checkstring(L, 1);
  int64_t ntotal, navail, nfree;
  int res;

#ifndef _WIN32
  struct statvfs buf;

  sys_vm_leave(L);
  res = statvfs(path, &buf);
  sys_vm_enter(L);

  ntotal = buf.f_blocks * buf.f_frsize;
  nfree = buf.f_bfree * buf.f_bsize;
  navail = buf.f_bavail * buf.f_bsize;
#else
  ULARGE_INTEGER na, nt, nf;

  SetErrorMode(SEM_FAILCRITICALERRORS);  /* for floppy disks */
  {
    void *os_path = utf8_to_filename(path);
    if (!os_path)
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

    sys_vm_leave(L);
    res = is_WinNT
     ? !GetDiskFreeSpaceExW(os_path, &na, &nt, &nf)
     : !GetDiskFreeSpaceExA(os_path, &na, &nt, &nf);

    free(os_path);
    sys_vm_enter(L);
  }

  ntotal = (int64_t) nt.QuadPart;
  nfree = (int64_t) nf.QuadPart;
  navail = (int64_t) na.QuadPart;
#endif
  if (!res) {
    lua_pushnumber(L, (lua_Number) ntotal);
    lua_pushnumber(L, (lua_Number) navail);
    lua_pushnumber(L, (lua_Number) nfree);
    return 3;
  }
  return sys_seterror(L, 0);
}
Example #5
0
/*
 * Arguments: binary_address (string)
 * Returns: [host_name (string)]
 */
static int
sock_getnameinfo (lua_State *L)
{
  int len, af;
  const char *addr = sock_checkladdr(L, 1, &len, &af);
  struct sock_addr sa;
  void *inp = sock_addr_get_inp(&sa, af);
  const int in_len = sock_addr_get_inlen(af);
#ifdef USE_GAI
  char host[NI_MAXHOST];
#else
  struct hostent *hp;
#endif
  int gai_errno;

  memset(&sa, 0, sizeof(struct sock_addr));
  sa.u.addr.sa_family = (short) af;
  memcpy(inp, addr, in_len);

#ifdef USE_GAI
  sys_vm_leave(L);
  gai_errno = getnameinfo(&sa.u.addr, sizeof(struct sock_addr),
   host, sizeof(host), NULL, 0, NI_NAMEREQD);
  sys_vm_enter(L);

  if (gai_errno) goto err;

  lua_pushstring(L, host);
#else
  sys_vm_leave(L);
  hp = gethostbyaddr(inp, in_len, af);
  sys_vm_enter(L);

  if (!hp) {
    gai_errno = h_errno;
    goto err;
  }

  lua_pushstring(L, hp->h_name);
#endif
  return 1;
 err:
  return sock_gai_seterror(L, gai_errno);
}
Example #6
0
/*
 * Arguments: rand_udata, [upper_bound (number)
 *	| buffer (ludata), buffer_length (number)]
 * Returns: number
 */
static int
rand_next (lua_State *L)
{
  const int is_udata = lua_isuserdata(L, 2);
  const unsigned int ub = is_udata ? 0 : lua_tointeger(L, 2);
  unsigned int num;
  unsigned char *buf = is_udata ? lua_touserdata(L, 2) : #
  const int len = is_udata ? luaL_checkinteger(L, 3) : (int) sizeof(num);
#ifndef _WIN32
  fd_t fd = (fd_t) lua_unboxinteger(L, 1, RAND_TYPENAME);
  int nr;

  sys_vm_leave(L);
  do nr = read(fd, (char *) buf, len);
  while (nr == -1 && sys_eintr());
  sys_vm_enter(L);

  if (nr == len) {
#else
  HCRYPTPROV prov = (HCRYPTPROV) lua_unboxpointer(L, 1, RAND_TYPENAME);
  int res;

  sys_vm_leave(L);
  res = CryptGenRandom(prov, len, buf);
  sys_vm_enter(L);

  if (res) {
#endif
    lua_pushinteger(L, is_udata ? 1
     : (ub ? num % ub : num));
    return 1;
  }
  return sys_seterror(L, 0);
}


#define RAND_METHODS \
  {"random",		sys_random}

static luaL_Reg rand_meth[] = {
  {"__call",		rand_next},
  {"__gc",		rand_close},
  {NULL, NULL}
};
Example #7
0
/*
 * Arguments: fd_udata, path (string), [permissions (number)]
 * Returns: [fd_udata]
 */
static int
sys_create (lua_State *L)
{
  fd_t fd, *fdp = checkudata(L, 1, FD_TYPENAME);
  const char *path = luaL_checkstring(L, 2);
#ifndef _WIN32
  mode_t perm = (mode_t) luaL_optinteger(L, 3, SYS_FILE_PERMISSIONS);
#endif

#ifndef _WIN32
  sys_vm_leave(L);
  fd = creat(path, perm);
  sys_vm_enter(L);
#else
  {
    const int flags = GENERIC_WRITE;
    const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE
     | FILE_SHARE_DELETE;
    const DWORD creation = CREATE_ALWAYS;
    const DWORD attr = FILE_ATTRIBUTE_NORMAL
     | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION;

    void *os_path = utf8_to_filename(path);
    if (!os_path)
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

    sys_vm_leave(L);
    fd = is_WinNT
     ? CreateFileW(os_path, flags, share, NULL, creation, attr, NULL)
     : CreateFileA(os_path, flags, share, NULL, creation, attr, NULL);

    free(os_path);
    sys_vm_enter(L);
  }
#endif

  if (fd != (fd_t) -1) {
    *fdp = fd;
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}
Example #8
0
/*
 * Arguments: milliseconds (number), [don't interrupt (boolean)]
 */
static int
thread_sleep (lua_State *L)
{
  const int msec = (int) lua_tointeger(L, 1);
  const int not_intr = lua_toboolean(L, 2);

  sys_vm_leave(L);
  sys_thread_sleep(msec, not_intr);
  sys_vm_enter(L);
  return 0;
}
Example #9
0
/*
 * Arguments: existing_path (string), new_path (string)
 * Returns: [boolean]
 */
static int
sys_rename (lua_State *L)
{
  const char *old = luaL_checkstring(L, 1);
  const char *new = luaL_checkstring(L, 2);
  int res;

#ifndef _WIN32
  sys_vm_leave(L);
  res = rename(old, new);
  sys_vm_enter(L);
#else
  {
    void *os_old = utf8_to_filename(old);
    void *os_new = utf8_to_filename(new);
    if (!os_old || !os_new) {
      free(os_old);
      free(os_new);
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);
    }

    sys_vm_leave(L);
    res = is_WinNT
     ? !MoveFileW(os_old, os_new)
     : !MoveFileA(os_old, os_new);

    free(os_old);
    free(os_new);
    sys_vm_enter(L);
  }
#endif

  if (!res) {
    lua_pushboolean(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}
Example #10
0
static int
thread_yield (lua_State *L)
{
  (void) L;

  sys_vm_leave(L);
#ifndef _WIN32
  sched_yield();
#else
  Sleep(0);
#endif
  sys_vm_enter(L);
  return 0;
}
Example #11
0
/*
 * Arguments: ecb_udata, {string | membuf_udata} ...
 * Returns: [success/partial (boolean), count (number)]
 */
static int
ecb_write (lua_State *L)
{
  LPEXTENSION_CONTROL_BLOCK ecb = lua_unboxpointer(L, 1, ECB_TYPENAME);
  size_t n = 0;  /* number of chars actually write */
  int i, narg = lua_gettop(L);

  if (ecb->dwHttpStatusCode & ECB_STATUS_HEADERS_SEND) {
    ecb->dwHttpStatusCode ^= ECB_STATUS_HEADERS_SEND;

    lua_pushfstring(L, "HTTP/1.1 %d\r\n",
     (ecb->dwHttpStatusCode & ECB_STATUS_MASK));

    lua_rawgetp(L, LUA_REGISTRYINDEX, ecb);

    lua_pushliteral(L, "\r\n");
    lua_concat(L, 3);

    lua_insert(L, 2);
    ++narg;
  }

  for (i = 2; i <= narg; ++i) {
    struct sys_buffer sb;
    int nw;

    if (!sys_buffer_read_init(L, i, &sb)
     || sb.size == 0)  /* don't close the connection */
      continue;
    sys_vm_leave();
    {
      DWORD l = sb.size;
      nw = ecb->WriteClient(ecb->ConnID, sb.ptr.w, &l, 0)
       ? (int) l : -1;
    }
    sys_vm_enter();
    if (nw == -1) {
      if (n > 0) break;
      return sys_seterror(L, 0);
    }
    n += nw;
    sys_buffer_read_next(&sb, nw);
    if ((size_t) nw < sb.size) break;
  }
  lua_pushboolean(L, (i > narg));
  lua_pushinteger(L, n);
  return 2;
}
Example #12
0
static int
channel_get (lua_State *L)
{
    struct channel *chan = checkudata(L, 1, CHANNEL_TYPENAME);
    const msec_t timeout = lua_isnoneornil(L, 2)
     ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
    int nput;
    int idx;
    int i;

    lua_settop(L, 1);
    lua_getfenv(L, 1);  /* storage */
    lua_insert(L, 1);

    sys_vm_leave();

    thread_critsect_enter(&chan->mutex);
    thread_cond_signal(&chan->get);

    /* wait signal */
    while (chan->n == 0) {
        thread_cond_wait(&chan->put, &chan->mutex, timeout);
    }

    /* get from storage */
    idx = chan->idx + 1;

    lua_rawgeti(L, 1, idx);
    nput = lua_tointeger(L, -1);
    lua_pushnil(L);
    lua_rawseti(L, 1, idx);
    chan->idx = idx + nput;

    for (i = chan->idx; i > idx; --i) {
        lua_rawgeti(L, 1, i);
        lua_pushnil(L);
        lua_rawseti(L, 1, i);
    }

    if (chan->idx == chan->top) chan->idx = chan->top = 0;
    chan->n--;

    thread_critsect_leave(&chan->mutex);

    sys_vm_enter();

    return nput;
}
Example #13
0
/*
 * Arguments: membuf_udata
 * Returns: [membuf_udata]
 */
static int
mem_sync (lua_State *L)
{
    struct membuf *mb = checkudata(L, 1, MEM_TYPENAME);
    int res;

    sys_vm_leave();
#ifndef _WIN32
    res = msync(mb->data, mb->len, MS_SYNC);
#else
    res = !FlushViewOfFile(mb->data, 0);
#endif
    sys_vm_enter();

    return !res ? 1 : 0;
}
Example #14
0
/*
 * Arguments: sd_udata, [membuf_udata, count (number)]
 * Returns: [string | false (EAGAIN)]
 */
static int
sock_read (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    size_t n = !lua_isnumber(L, -1) ? ~((size_t) 0)
     : (size_t) lua_tointeger(L, -1);
    const size_t len = n;  /* how much total to read */
    size_t rlen;  /* how much to read */
    int nr;  /* number of bytes actually read */
    struct sys_buffer sb;
    char buf[SYS_BUFSIZE];

    sys_buffer_write_init(L, 2, &sb, buf, sizeof(buf));
    do {
	rlen = (n <= sb.size) ? n : sb.size;
	sys_vm_leave();
#ifndef _WIN32
	do nr = read(sd, sb.ptr.w, rlen);
	while (nr == -1 && SYS_ERRNO == EINTR);
#else
	{
	    WSABUF buf = {rlen, sb.ptr.w};
	    DWORD l, flags = 0;
	    nr = !WSARecv(sd, &buf, 1, &l, &flags, NULL, NULL) ? l : -1;
	}
#endif
	sys_vm_enter();
	if (nr == -1) break;
	n -= nr;  /* still have to read `n' bytes */
    } while ((n != 0L && nr == (int) rlen)  /* until end of count or eof */
     && sys_buffer_write_next(L, &sb, buf, 0));
    if (nr <= 0 && len == n) {
	if (!nr || !SYS_EAGAIN(SYS_ERRNO)) goto err;
	lua_pushboolean(L, 0);
    } else {
	if (!sys_buffer_write_done(L, &sb, buf, nr))
	    lua_pushinteger(L, len - n);
    }
    return 1;
 err:
    return sys_seterror(L, 0);
}
Example #15
0
/*
 * Arguments: thread_udata, [timeout (milliseconds)]
 * Returns: [status (number) | timeout (false) | no_workers (true)]
 */
static int
thread_wait (lua_State *L)
{
  struct sys_thread *td = checkudata(L, 1, THREAD_TYPENAME);
  const msec_t timeout = lua_isnoneornil(L, 2)
   ? TIMEOUT_INFINITE : (msec_t) lua_tointeger(L, 2);
  int res;

  if (thread_isvm(td)) {
    res = thread_waitvm(td->vmtd, timeout);
    if (!res) {
      lua_pushboolean(L, 1);  /* no workers */
      return 1;
    }
  } else {
    if (td->flags == SYS_THREAD_KILLED)
      goto result;

#ifndef _WIN32
    do {
      res = thread_cond_wait_vm(&td->cond, td, timeout);
      sys_thread_check(td, L);
    } while (td->flags != SYS_THREAD_KILLED && !res);
#else
    sys_vm_leave(L);
    res = thread_handle_wait(td->tid, timeout);
    sys_vm_enter(L);
#endif
  }

  if (res >= 0) {
    if (res == 1) {
      lua_pushboolean(L, 0);
      return 1;  /* timed out */
    }
 result:
    lua_pushinteger(L, td->exit_status);
    return 1;
  }
  return sys_seterror(L, 0);
}
Example #16
0
static int
channel_put (lua_State *L)
{
    struct sys_thread *td = sys_get_thread();
    struct channel *chan = checkudata(L, 1, CHANNEL_TYPENAME);
    int nput = lua_gettop(L) - 1;

    if (!td) luaL_argerror(L, 0, "Threading not initialized");
    if (!nput) luaL_argerror(L, 2, "data expected");

    lua_getfenv(L, 1);  /* get the storage table */
    lua_insert(L, 1);

    sys_vm_leave();

    thread_critsect_enter(&chan->mutex);
    thread_cond_signal(&chan->put);

    /* move the data to storage */
    {
	int top = chan->top;

	lua_pushinteger(L, nput);
	do {
	    lua_rawseti(L, 1, ++top);
	} while (nput--);
	chan->top = top;
        chan->n++;
    }

    while (chan->n > chan->max) {
        thread_cond_wait(&chan->get, &chan->mutex, TIMEOUT_INFINITE);
    }

    thread_critsect_leave(&chan->mutex);

    sys_vm_enter();
    return 0;
}
Example #17
0
/*
 * Arguments: sd_udata, sock_addr_udata
 * Returns: [sd_udata | false (EINPROGRESS)]
 */
static int
sock_connect (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    struct sock_addr *sap = checkudata(L, 2, SA_TYPENAME);
    int res;

    sys_vm_leave();
    do res = connect(sd, &sap->u.addr, sap->addrlen);
    while (res == -1 && SYS_ERRNO == EINTR);
    sys_vm_enter();

    if (!res || SYS_ERRNO == EINPROGRESS || SYS_ERRNO == EALREADY
#if defined(__FreeBSD__)
     || SYS_ERRNO == EADDRINUSE
#endif
     || SYS_EAGAIN(SYS_ERRNO)) {
	if (res) lua_pushboolean(L, 0);
	else lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #18
0
/*
 * Arguments: sd_udata, {string | membuf_udata},
 *	[to (sock_addr_udata), options (string) ...]
 * Returns: [success/partial (boolean), count (number)]
 */
static int
sock_send (lua_State *L)
{
    static const int o_flags[] = {
	MSG_OOB, MSG_DONTROUTE,
    };
    static const char *const o_names[] = {
	"oob", "dontroute", NULL
    };
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    const struct sock_addr *to = !lua_isuserdata(L, 3) ? NULL
     : checkudata(L, 3, SA_TYPENAME);
    struct sys_buffer sb;
    int nw;  /* number of chars actually send */
    unsigned int i, flags = 0;

    if (!sys_buffer_read_init(L, 2, &sb))
	luaL_argerror(L, 2, "buffer expected");
    for (i = lua_gettop(L); i > 3; --i) {
	flags |= o_flags[luaL_checkoption(L, i, NULL, o_names)];
    }
    sys_vm_leave();
    do nw = !to ? send(sd, sb.ptr.r, sb.size, flags)
     : sendto(sd, sb.ptr.r, sb.size, flags, &to->u.addr, to->addrlen);
    while (nw == -1 && SYS_ERRNO == EINTR);
    sys_vm_enter();
    if (nw == -1) {
	if (!SYS_EAGAIN(SYS_ERRNO))
	    return sys_seterror(L, 0);
	nw = 0;
    } else {
	sys_buffer_read_next(&sb, nw);
    }
    lua_pushboolean(L, ((size_t) nw == sb.size));
    lua_pushinteger(L, nw);
    return 2;
}
Example #19
0
/*
 * Returns: [interfaces (table)]
 */
static int
sock_getifaddrs (lua_State *L)
{
  struct sock_addr *sap;
  int i, res;

#ifndef _WIN32
  struct ifaddrs *result, *rp;

  sys_vm_leave(L);
  res = getifaddrs(&result);
  sys_vm_enter(L);
#else
  INTERFACE_INFO result[8192], *rp;
  SOCKET sd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAGS);
  DWORD n;

  sys_vm_leave(L);
  res = WSAIoctl(sd, SIO_GET_INTERFACE_LIST, NULL, 0,
   result, sizeof(result), &n, NULL, NULL);

  closesocket(sd);
  sys_vm_enter(L);
#endif

  if (res == -1)
    return sys_seterror(L, 0);

  lua_createtable(L, 8, 0);
  rp = result;
#ifndef _WIN32
  for (i = 0; rp; rp = rp->ifa_next) {
#else
  for (i = 0; n--; ++rp) {
#endif
#ifndef _WIN32
    sap = (struct sock_addr *) rp->ifa_addr;
#else
    sap = (struct sock_addr *) &rp->iiAddress;
#endif
    if (!sap || sap->u.addr.sa_family == AF_UNSPEC)
      continue;

    lua_newtable(L);
    {
      const int af = sap->u.addr.sa_family;

      if (af == AF_INET
#ifdef AF_INET6
       || af == AF_INET6
#endif
      ) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "addr");
      }

      {
        const char *s = NULL;

        switch (af) {
        case AF_INET: s = "INET"; break;
#ifdef AF_INET6
        case AF_INET6: s = "INET6"; break;
#endif
#ifdef AF_LOCAL
        case AF_LOCAL: s = "LOCAL"; break;
#endif
#ifdef AF_AX25
        case AF_AX25: s = "AX25"; break;
#endif
#ifdef AF_IPX
        case AF_IPX: s = "IPX"; break;
#endif
#ifdef AF_APPLETALK
        case AF_APPLETALK: s = "APPLETALK"; break;
#endif
#ifdef AF_NETROM
        case AF_NETROM: s = "NETROM"; break;
#endif
#ifdef AF_BRIDGE
        case AF_BRIDGE: s = "BRIDGE"; break;
#endif
#ifdef AF_ATMPVC
        case AF_ATMPVC: s = "ATMPVC"; break;
#endif
#ifdef AF_X25
        case AF_X25: s = "X25"; break;
#endif
#ifdef AF_ROSE
        case AF_ROSE: s = "ROSE"; break;
#endif
#ifdef AF_DECnet
        case AF_DECnet: s = "DECnet"; break;
#endif
#ifdef AF_NETBEUI
        case AF_NETBEUI: s = "NETBEUI"; break;
#endif
#ifdef AF_SECURITY
        case AF_SECURITY: s = "SECURITY"; break;
#endif
#ifdef AF_KEY
        case AF_KEY: s = "KEY"; break;
#endif
#ifdef AF_NETLINK
        case AF_NETLINK: s = "NETLINK"; break;
#endif
#ifdef AF_PACKET
        case AF_PACKET: s = "PACKET"; break;
#endif
#ifdef AF_ASH
        case AF_ASH: s = "ASH"; break;
#endif
#ifdef AF_ECONET
        case AF_ECONET: s = "ECONET"; break;
#endif
#ifdef AF_ATMSVC
        case AF_ATMSVC: s = "ATMSVC"; break;
#endif
#ifdef AF_RDS
        case AF_RDS: s = "RDS"; break;
#endif
#ifdef AF_SNA
        case AF_SNA: s = "SNA"; break;
#endif
#ifdef AF_IRDA
        case AF_IRDA: s = "IRDA"; break;
#endif
#ifdef AF_PPPOX
        case AF_PPPOX: s = "PPPOX"; break;
#endif
#ifdef AF_WANPIPE
        case AF_WANPIPE: s = "WANPIPE"; break;
#endif
#ifdef AF_LLC
        case AF_LLC: s = "LLC"; break;
#endif
#ifdef AF_CAN
        case AF_CAN: s = "CAN"; break;
#endif
#ifdef AF_TIPC
        case AF_TIPC: s = "TIPC"; break;
#endif
#ifdef AF_BLUETOOTH
        case AF_BLUETOOTH: s = "BLUETOOTH"; break;
#endif
#ifdef AF_IUCV
        case AF_IUCV: s = "IUCV"; break;
#endif
#ifdef AF_RXRPC
        case AF_RXRPC: s = "RXRPC"; break;
#endif
#ifdef AF_ISDN
        case AF_ISDN: s = "ISDN"; break;
#endif
#ifdef AF_PHONET
        case AF_PHONET: s = "PHONET"; break;
#endif
#ifdef AF_IEEE802154
        case AF_IEEE802154: s = "IEEE802154"; break;
#endif
        default: s = "UNKNOWN";
        }
        if (s) {
          lua_pushstring(L, s);
          lua_setfield(L, -2, "family");
        }
      }

#ifndef _WIN32
      sap = (struct sock_addr *) rp->ifa_netmask;
#else
      sap = (struct sock_addr *) &rp->iiNetmask;
#endif
      if (sap) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "netmask");
      }

#ifndef _WIN32
      sap = (struct sock_addr *) rp->ifa_broadaddr;
#else
      sap = (struct sock_addr *) &rp->iiBroadcastAddress;
#endif
      if (sap) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "broadaddr");
      }

      lua_createtable(L, 0, 5);
      {
#ifndef _WIN32
        const int flags = rp->ifa_flags;
#else
        const int flags = rp->iiFlags;
#endif

        lua_pushboolean(L, flags & IFF_UP);
        lua_setfield(L, -2, "up");

        lua_pushboolean(L, flags & IFF_BROADCAST);
        lua_setfield(L, -2, "broadcast");

        lua_pushboolean(L, flags & IFF_LOOPBACK);
        lua_setfield(L, -2, "loopback");

        lua_pushboolean(L, flags & IFF_POINTOPOINT);
        lua_setfield(L, -2, "pointtopoint");

        lua_pushboolean(L, flags & IFF_MULTICAST);
        lua_setfield(L, -2, "multicast");
      }
      lua_setfield(L, -2, "flags");
    }
    lua_rawseti(L, -2, ++i);
  }
#ifndef _WIN32
  freeifaddrs(result);
#endif
  return 1;
}


/*
 * Arguments: text_address (string), [ip4_tonumber (true)]
 * Returns: [binary_address (string | number)]
 */
static int
sock_inet_pton (lua_State *L)
{
  const char *src = luaL_checkstring(L, 1);
  const int to_ip4 = lua_toboolean(L, 2);
  const int af = (!to_ip4 && strchr(src, ':')) ? AF_INET6 : AF_INET;
  struct sock_addr sa;
  void *inp = sock_addr_get_inp(&sa, af);
  const int in_len = sock_addr_get_inlen(af);
#ifdef _WIN32
  union sys_rwptr src_ptr;  /* to avoid "const cast" warning */
#endif

  memset(&sa, 0, sizeof(struct sock_addr));
  if (*src == '*') goto end;

#ifndef _WIN32
  if (inet_pton(af, src, inp) == 1) {
#else
  sa.addrlen = sizeof(sa);
  src_ptr.r = src;
  if (!WSAStringToAddressA(src_ptr.w, af, NULL,
   &sa.u.addr, &sa.addrlen)) {
#endif
 end:
    if (to_ip4)
      lua_pushnumber(L, ntohl(*((unsigned long *) inp)));
    else
      lua_pushlstring(L, inp, in_len);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: binary_address (string | number)
 * Returns: [text_address (string)]
 */
static int
sock_inet_ntop (lua_State *L)
{
  const int is_ip4 = (lua_type(L, 1) == LUA_TNUMBER);
  unsigned long ip4;
  int in_len, af;
  const char *src;
  char buf[48];

  if (is_ip4) {
    const lua_Number num = lua_tonumber(L, 1);

    in_len = 4;
    af = AF_INET;
    ip4 = htonl((unsigned long) num);
    src = (const char *) &ip4;
  } else {
    src = sock_checkladdr(L, 1, &in_len, &af);
  }

#ifndef _WIN32
  if (inet_ntop(af, src, buf, sizeof(buf)) == NULL)
    goto err;
#else
  {
    struct sock_addr sa;
    void *inp = sock_addr_get_inp(&sa, af);
    const int sl = (af == AF_INET) ? sizeof(struct sockaddr_in)
     : sizeof(struct sockaddr_in6);
    DWORD buflen = sizeof(buf);

    memset(&sa, 0, sizeof(struct sock_addr));
    memcpy(inp, src, in_len);
    sa.u.addr.sa_family = (short) af;

    if (WSAAddressToStringA(&sa.u.addr, sl, NULL, buf, &buflen)
     || buflen >= sizeof(buf))
      goto err;
  }
#endif
  lua_pushstring(L, buf);
  return 1;
 err:
  return sys_seterror(L, 0);
}


/*
 * Returns: sock_addr_udata
 */
static int
sock_addr_new (lua_State *L)
{
  lua_newuserdata(L, sizeof(struct sock_addr));
  luaL_getmetatable(L, SA_TYPENAME);
  lua_setmetatable(L, -2);
  return 1;
}

/*
 * Arguments: sock_addr_udata, [port (number), binary_address (string)]
 * Returns: sock_addr_udata | port (number), binary_address (string)
 */
static int
sock_addr_inet (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

  if (lua_gettop(L) == 1) {
    const int af = sap->u.addr.sa_family;

    if (af == AF_INET) {
      lua_pushinteger(L, ntohs(sap->u.in.sin_port));
      lua_pushlstring(L, (char *) &sap->u.in.sin_addr,
       sizeof(struct in_addr));
    } else if (af == AF_INET6) {
      lua_pushinteger(L, ntohs(sap->u.in6.sin6_port));
      lua_pushlstring(L, (char *) &sap->u.in6.sin6_addr,
       sizeof(struct in6_addr));
    } else
      return 0;
    return 2;
  } else {
    const int port = (int) lua_tointeger(L, 2);
    int in_len = SOCK_ADDR_LEN, af = AF_INET;
    const char *addr = lua_isnoneornil(L, 3) ? NULL
     : sock_checkladdr(L, 3, &in_len, &af);

    memset(sap, 0, sizeof(struct sock_addr));
    sap->u.addr.sa_family = (short) af;
    if (af == AF_INET) {
      sap->u.in.sin_port = htons((unsigned short) port);
      if (addr)
        memcpy(&sap->u.in.sin_addr, addr, in_len);
      sap->addrlen = sizeof(struct sockaddr_in);
    } else {
      sap->u.in6.sin6_port = htons((unsigned short) port);
      if (addr)
        memcpy(&sap->u.in6.sin6_addr, addr, in_len);
      sap->addrlen = sizeof(struct sockaddr_in6);
    }
    lua_settop(L, 1);
    return 1;
  };
}

/*
 * Arguments: sock_addr_udata, [path (string)]
 * Returns: sock_addr_udata | path (string)
 */
static int
sock_addr_file (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

#ifndef _WIN32
  if (lua_gettop(L) == 1) {
    if (sap->u.addr.sa_family == AF_LOCAL) {
      lua_pushstring(L, sap->u.un.sun_path);
      return 1;
    }
  } else {
    size_t len;
    const char *path = luaL_checklstring(L, 2, &len);

    if (len < sizeof(sap->u.un.sun_path)) {
      sap->u.un.sun_family = AF_LOCAL;
      sap->addrlen = ++len;
      memcpy(sap->u.un.sun_path, path, len);

      lua_settop(L, 1);
      return 1;
    }
  };
#else
  (void) sap;
#endif
  return 0;
}

/*
 * Arguments: sock_addr_udata, sd_udata
 * Returns: [sock_addr_udata]
 */
static int
sock_addr_getsockname (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);
  sd_t sd = (sd_t) lua_unboxinteger(L, 2, SD_TYPENAME);

  sap->addrlen = SOCK_ADDR_LEN;
  if (!getsockname(sd, &sap->u.addr, &sap->addrlen)) {
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: sock_addr_udata, sd_udata
 * Returns: [sock_addr_udata]
 */
static int
sock_addr_getpeername (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);
  sd_t sd = (sd_t) lua_unboxinteger(L, 2, SD_TYPENAME);

  sap->addrlen = SOCK_ADDR_LEN;
  if (!getpeername(sd, &sap->u.addr, &sap->addrlen)) {
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: sock_addr_udata
 * Returns: string
 */
static int
sock_addr_tostring (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

  lua_pushfstring(L, SA_TYPENAME " (%p)", sap);
  return 1;
}


#define ADDR_METHODS \
  {"getaddrinfo",	sock_getaddrinfo}, \
  {"getnameinfo",	sock_getnameinfo}, \
  {"getifaddrs",	sock_getifaddrs}, \
  {"inet_pton",		sock_inet_pton}, \
  {"inet_ntop",		sock_inet_ntop}, \
  {"addr",		sock_addr_new}

static luaL_Reg addr_meth[] = {
  {"inet",		sock_addr_inet},
  {"file",		sock_addr_file},
  {"getsockname",	sock_addr_getsockname},
  {"getpeername",	sock_addr_getpeername},
  {"__tostring",	sock_addr_tostring},
  {NULL, NULL}
};
Example #20
0
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
  struct event *ev_ready;
  struct kevent *kev = evq->kev_list;
  struct timespec ts, *tsp;
  int nready;

  if (timeout != 0L) {
    timeout = timeout_get(evq->tq, timeout, evq->now);
    if (timeout == 0L) {
      ev_ready = timeout_process(evq->tq, NULL, evq->now);
      goto end;
    }
  }
  if (timeout == TIMEOUT_INFINITE)
    tsp = NULL;
  else {
    ts.tv_sec = timeout / 1000;
    ts.tv_nsec = (timeout % 1000) * 1000000;
    tsp = &ts;
  }

  sys_vm_leave();
  nready = kevent(evq->kqueue_fd, kev, evq->nchanges, kev, NEVENT, tsp);
  sys_vm_enter();

  evq->nchanges = 0;
  evq->now = sys_milliseconds();

  if (nready == -1)
    return (errno == EINTR) ? 0 : EVQ_FAILED;

  if (tsp) {
    if (!nready) {
      ev_ready = !evq->tq ? NULL
       : timeout_process(evq->tq, NULL, evq->now);
      if (ev_ready) goto end;
      return EVQ_TIMEOUT;
    }

    timeout = evq->now;
  }

  ev_ready = NULL;
  for (; nready--; ++kev) {
    struct event *ev;
    const int flags = kev->flags;
    const int filter = kev->filter;

    if (flags & EV_ERROR)
      continue;

    if (filter == EVFILT_SIGNAL) {
      ev_ready = signal_process_actives(evq, kev->ident,
       ev_ready, timeout);
      continue;
    }

    ev = (struct event *) kev->udata;
    if (!ev) {
      ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
      continue;
    }

    ev->flags |= (filter == EVFILT_READ ? EVENT_READ_RES : EVENT_WRITE_RES)
     | ((flags & EV_EOF) ? EVENT_EOF_RES : 0);

    if (ev->flags & EVENT_ACTIVE)
      continue;

    ev->flags |= EVENT_ACTIVE;
    if (ev->flags & EVENT_ONESHOT)
      evq_del(ev, 1);
    else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
      timeout_reset(ev, timeout);

    ev->next_ready = ev_ready;
    ev_ready = ev;
  }
  if (!ev_ready) return 0;
 end:
  evq->ev_ready = ev_ready;
  return 0;
}
Example #21
0
/*
 * Arguments: dir_udata, directory (string)
 *
 * Returns: [filename (string), is_directory (boolean)]
 * |
 * Returns (win32): [drive_letter (string: A: .. Z:), drive_type (string)]
 */
static int
sys_dir_next (lua_State *L)
{
  struct dir *dp = checkudata(L, 1, DIR_TYPENAME);

  if (lua_gettop(L) == 2) {  /* 'for' start? */
    /* return generator (dir_udata) */
    lua_pushvalue(L, 1);
    return sys_dir_open(L, 2, dp);
  } else {  /* 'for' step */
    char *filename;

#ifndef _WIN32
    struct dirent *entry;

    if (!dp->data)
      return 0;
    do {
      sys_vm_leave(L);
      entry = readdir(dp->data);
      sys_vm_enter(L);

      if (!entry) {
        closedir(dp->data);
        dp->data = NULL;
        return 0;
      }
      filename = entry->d_name;
    } while (filename[0] == '.' && (filename[1] == '\0'
     || (filename[1] == '.' && filename[2] == '\0')));

    lua_pushstring(L, filename);
    lua_pushboolean(L, entry->d_type & DT_DIR);
    return 2;
#else
    filename = (char *) dp->data.cFileName;

    if (dp->is_root) {
      while (++*filename <= 'Z') {
        const char *type;

        switch (GetDriveTypeA(filename)) {
        case DRIVE_REMOVABLE: type = "removable"; break;
        case DRIVE_FIXED: type = "fixed"; break;
        case DRIVE_REMOTE: type = "remote"; break;
        case DRIVE_CDROM: type = "cdrom"; break;
        case DRIVE_RAMDISK: type = "ramdisk"; break;
        default: continue;
        }
        lua_pushlstring(L, filename, 2);
        lua_pushstring(L, type);
        return 2;
      }
      return 0;
    }

    if (dp->h == INVALID_HANDLE_VALUE)
      return 0;
    for (; ; ) {
      int res, is_dots = 1;
      {
        char *path = filename_to_utf8(filename);
        if (!path)
          return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

        if (!(path[0] == '.' && (path[1] == '\0'
         || (path[1] == '.' && path[2] == '\0')))) {
          lua_pushstring(L, path);
          lua_pushboolean(L,
           dp->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
          is_dots = 0;
        }

        free(path);
      }

      sys_vm_leave(L);
      res = is_WinNT
       ? FindNextFileW(dp->h, &dp->data)
       : FindNextFileA(dp->h, (WIN32_FIND_DATAA *) &dp->data);
      sys_vm_enter(L);

      if (!res) {
        FindClose(dp->h);
        dp->h = INVALID_HANDLE_VALUE;
        return is_dots ? 0 : 2;
      }
      if (!is_dots) break;
    }
    return 2;
#endif
  }
}
Example #22
0
/*
 * Arguments: ..., directory (string)
 */
static int
sys_dir_open (lua_State *L, const int idx, struct dir *dp)
{
  const char *dir = luaL_checkstring(L, idx);

#ifndef _WIN32
  if (dp->data)
    closedir(dp->data);

  sys_vm_leave(L);
  dp->data = opendir(*dir == '\0' ? "/" : dir);
  sys_vm_enter(L);

  if (dp->data) return 1;
#else
  char *filename = (char *) dp->data.cFileName;

  if (*dir == '\0' || (*dir == '/' && dir[1] == '\0')) {
    /* list drive letters */
    *filename++ = 'A' - 1;
    *filename++ = ':';
    *filename++ = '\\';
    *filename = '\0';

    dp->is_root = 1;
    return 1;
  } else {
    const int len = lua_rawlen(L, idx);

    /* build search path */
    if (len >= MAX_PATH - 2)  /* concat "\\*" */
      return 0;
    memcpy(filename, dir, len);
    filename += len - 1;
    if (*filename != '\\' && *filename != '/')
      *(++filename) = '\\';
    *(++filename) = '*';
    *(++filename) = '\0';

    if (dp->h != INVALID_HANDLE_VALUE)
      FindClose(dp->h);

    {
      void *os_path = utf8_to_filename((char *) dp->data.cFileName);
      if (!os_path)
        return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

      sys_vm_leave(L);
      dp->h = is_WinNT
       ? FindFirstFileW(os_path, &dp->data)
       : FindFirstFileA(os_path, (WIN32_FIND_DATAA *) &dp->data);

      free(os_path);
      sys_vm_enter(L);
    }

    if (dp->h != INVALID_HANDLE_VALUE) {
      dp->is_root = 0;
      return 1;
    }
  }
#endif
  return sys_seterror(L, 0);
}
Example #23
0
/*
 * Arguments: filename (string) | function_dump (string),
 *	[arguments (string | number | boolean | lightuserdata) ...]
 * Returns: [thread_ludata]
 */
static int
thread_runvm (lua_State *L)
{
    const char *path = luaL_checkstring(L, 1);
    lua_State *NL = NULL;
    struct sys_vmthread *vmtd = (struct sys_vmthread *) sys_get_thread();
#ifndef _WIN32
    pthread_attr_t attr;
#else
    HANDLE hThr;
#endif
    int res = 0;

    if (!vmtd) luaL_argerror(L, 0, "Threading not initialized");

    NL = luaL_newstate();
    if (!NL) goto err;

    thread_openlibs(NL);

    if (path[0] == LUA_SIGNATURE[0]
     ? luaL_loadbuffer(NL, path, lua_rawlen(L, 1), "thread")
     : luaL_loadfile(NL, path)) {
	lua_pushstring(L, lua_tostring(NL, -1));  /* error message */
	lua_close(NL);
	lua_error(L);
    }

    /* Arguments */
    lua_pushlightuserdata(NL, vmtd);  /* master */
    {
	int i, top = lua_gettop(L);

	for (i = 2; i <= top; ++i) {
	    switch (lua_type(L, i)) {
	    case LUA_TSTRING:
		lua_pushstring(NL, lua_tostring(L, i));
		break;
	    case LUA_TNUMBER:
		lua_pushnumber(NL, lua_tonumber(L, i));
		break;
	    case LUA_TBOOLEAN:
		lua_pushboolean(NL, lua_toboolean(L, i));
		break;
	    case LUA_TLIGHTUSERDATA:
	    case LUA_TUSERDATA:
		lua_pushlightuserdata(NL, lua_touserdata(L, i));
		break;
	    default:
		luaL_argerror(L, i, "primitive type expected");
	    }
	}
    }

    if (vmthread_new(NL, &vmtd))
	goto err_clean;

#ifndef _WIN32
    res = pthread_attr_init(&attr);
    if (res) goto err_clean;
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    res = pthread_create(&vmtd->td.tid, &attr,
     (thread_func_t) thread_startvm, vmtd);
    pthread_attr_destroy(&attr);
    if (!res) {
#else
    hThr = (HANDLE) _beginthreadex(NULL, 0,
     (thread_func_t) thread_startvm, vmtd, 0, &vmtd->td.tid);
    if (hThr) {
	CloseHandle(hThr);
#endif
	lua_pushlightuserdata(L, vmtd);
	return 1;
    }
 err_clean:
    lua_close(NL);
 err:
    return sys_seterror(L, res);
}

/*
 * Arguments: thread_ludata
 */
static int
thread_interrupt (lua_State *L)
{
    struct sys_thread *td = lua_touserdata(L, 1);

    td->interrupted = 1;
#ifndef _WIN32
    pthread_kill(td->tid, SYS_SIGINTR);
#endif
    return 0;
}

static int
thread_yield (lua_State *L)
{
    (void) L;

    sys_vm_leave();
#ifndef _WIN32
    sched_yield();
#else
    Sleep(0);
#endif
    sys_vm_enter();
    return 0;
}
Example #24
0
/*
 * Arguments: fd_udata, [options ...:
 *	reset (string: "reset"),
 *	baud_rate (number),
 *	character_size (string: "cs5".."cs8"),
 *	parity (string: "parno", "parodd", "pareven"),
 *	stop_bits (string: "sb1", "sb2"),
 *	flow_controls (string: "foff", "frtscts", "fxio")]
 * Returns: [fd_udata]
 */
static int
comm_init (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  int i;

#ifndef _WIN32
  struct termios tio;

  if (tcgetattr(fd, &tio) == -1) goto err;
#else
  DCB dcb;

  dcb.DCBlength = sizeof(DCB);
  if (!GetCommState(fd, &dcb)) goto err;
#endif

  for (i = 2; i <= narg; ++i) {
#ifndef _WIN32
    tcflag_t mask = 0, flag = 0;
#endif

    if (lua_isnumber(L, i)) {
      const int baud_rate = lua_tointeger(L, i);
#ifndef _WIN32
      switch (baud_rate) {
      case 9600: flag = B9600; break;
      case 19200: flag = B19200; break;
      case 38400: flag = B38400; break;
      case 57600: flag = B57600; break;
      case 115200: flag = B115200; break;
      }
      if (cfsetispeed(&tio, flag) == -1
       || cfsetospeed(&tio, flag) == -1)
        goto err;
#else
      dcb.BaudRate = baud_rate;
#endif
    } else {
      const char *opt = lua_tostring(L, i);
      const char *endp = opt + lua_rawlen(L, i) - 1;

      if (!opt) continue;
      switch (*opt) {
      case 'r':  /* reset */
#ifndef _WIN32
        memset(&tio, 0, sizeof(struct termios));
#else
        memset(&dcb, 0, sizeof(DCB));
#endif
        continue;
      case 'c':  /* character size */
#ifndef _WIN32
        switch (*endp) {
        case '5': flag = CS5; break;
        case '6': flag = CS6; break;
        case '7': flag = CS7; break;
        default: flag = CS8;
        }
        mask = CSIZE;
#else
        dcb.ByteSize = (char) (*endp - '0');
#endif
        break;
      case 'p':  /* parity */
#ifndef _WIN32
        switch (*endp) {
        case 'd': flag = PARODD;
        case 'n': flag |= PARENB; break;
        default: flag = 0;  /* no parity */
        }
        mask = PARENB | PARODD;
#else
        {
          int parity;
          switch (*endp) {
          case 'd': parity = ODDPARITY; break;
          case 'n': parity = EVENPARITY; break;
          default: parity = 0;  /* no parity */
          }
          dcb.Parity = (char) parity;
          dcb.fParity = (parity != 0);
        }
#endif
        break;
      case 's':  /* stop bits */
#ifndef _WIN32
        if (*endp == '2') flag = CSTOPB;  /* else: one stop bit */
        mask = CSTOPB;
#else
        dcb.StopBits = (char) (*endp == '2' ? TWOSTOPBITS
         : ONESTOPBIT);
#endif
        break;
      case 'f':  /* flow controls */
        /* off */
#ifndef _WIN32
        mask = CRTSCTS;
        tio.c_iflag &= ~(IXON | IXOFF | IXANY);
#else
        dcb.fOutX = dcb.fInX = 0;
        dcb.fRtsControl = RTS_CONTROL_DISABLE;
        dcb.fOutxCtsFlow = 0;
#endif
        switch (opt[1]) {
        case 'x':  /* XON/XOFF */
#ifndef _WIN32
          tio.c_iflag |= (IXON | IXOFF | IXANY);
#else
          dcb.fOutX = dcb.fInX = 1;
#endif
          break;
        case 'r':  /* RTS/CTS */
#ifndef _WIN32
          flag = CRTSCTS;
#else
          dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
          dcb.fOutxCtsFlow = 1;
#endif
          break;
        }
        break;
      }
    }
#ifndef _WIN32
    tio.c_cflag &= ~mask;
    tio.c_cflag |= flag;
#endif
  }
#ifndef _WIN32
  tio.c_cflag |= CLOCAL | CREAD;

  if (!tcsetattr(fd, TCSANOW, &tio)) {
#else
  if (SetCommState(fd, &dcb)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
 err:
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, [controls (string: "dtr", "dsr", "rts", "cts") ...]
 * Returns: [fd_udata]
 */
static int
comm_control (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  int i;

#ifndef _WIN32
  int flags;

  if (ioctl(fd, TIOCMGET, &flags) == -1) goto err;
  flags &= ~(TIOCM_DTR | TIOCM_DSR | TIOCM_RTS | TIOCM_CTS
   | TIOCM_ST | TIOCM_SR | TIOCM_CAR | TIOCM_RNG);
#else
  DCB dcb;

  dcb.DCBlength = sizeof(DCB);
  if (!GetCommState(fd, &dcb)) goto err;
  dcb.fDtrControl = dcb.fOutxDsrFlow
   = dcb.fRtsControl = dcb.fOutxCtsFlow = 0;
#endif

  for (i = 2; i <= narg; ++i) {
    const char *s = lua_tostring(L, i);

    if (!s) continue;
    switch (*s) {
    case 'd':  /* DTR/DSR */
#ifndef _WIN32
      flags |= (s[1] == 't') ? TIOCM_DTR : TIOCM_DSR;
#else
      if (s[1] == 't') dcb.fDtrControl = 1;
      else dcb.fOutxDsrFlow = 1;
#endif
      break;
    case 'r':  /* RTS */
#ifndef _WIN32
      flags |= TIOCM_RTS;
#else
      dcb.fRtsControl = 1;
#endif
      break;
    case 'c':  /* CTS */
#ifndef _WIN32
      flags |= TIOCM_CTS;
#else
      dcb.fOutxCtsFlow = 1;
#endif
      break;
    }
  }
#ifndef _WIN32
  if (!ioctl(fd, TIOCMSET, &flags)) {
#else
  if (SetCommState(fd, &dcb)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
 err:
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, [read_timeout (milliseconds)]
 * Returns: [fd_udata]
 */
static int
comm_timeout (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int rtime = lua_tointeger(L, 2);

#ifndef _WIN32
  struct termios tio;

  if (tcgetattr(fd, &tio) == -1) goto err;
  tio.c_cc[VTIME] = rtime / 100;
  tio.c_cc[VMIN] = 0;

  if (!tcsetattr(fd, TCSANOW, &tio)) {
#else
  COMMTIMEOUTS timeouts;

  memset(&timeouts, 0, sizeof(COMMTIMEOUTS));
  timeouts.ReadIntervalTimeout = rtime ? (DWORD) rtime : MAXDWORD;
  timeouts.ReadTotalTimeoutMultiplier =
   timeouts.ReadTotalTimeoutConstant = rtime;

  if (SetCommTimeouts(fd, &timeouts)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
#ifndef _WIN32
 err:
#endif
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, in_buffer_size (number), out_buffer_size (number)
 * Returns: [fd_udata]
 */
static int
comm_queues (lua_State *L)
{
#ifndef _WIN32
  if (1) {
#else
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int rqueue = lua_tointeger(L, 2);
  const int wqueue = lua_tointeger(L, 3);

  if (SetupComm(fd, rqueue, wqueue)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
#ifdef _WIN32
  return sys_seterror(L, 0);
#endif
}

/*
 * Arguments: fd_udata, [mode (string: "rw", "r", "w")]
 * Returns: [fd_udata]
 */
static int
comm_purge (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const char *mode = lua_tostring(L, 2);
  int flags;

  flags = TCIOFLUSH;
  if (mode)
    switch (mode[0]) {
    case 'w': flags = TCOFLUSH; break;
    case 'r': if (!mode[1]) flags = TCIFLUSH;
    }
#ifndef _WIN32
  if (!tcflush(fd, flags)) {
#else
  if (PurgeComm(fd, flags)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, options (string: "car", "cts", "dsr", "ring") ...
 * Returns: [boolean ...]
 */
static int
comm_wait (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  unsigned long status = 0;
  int flags = 0;
  int i, res;

  for (i = 2; i <= narg; ++i) {
    const char *s = lua_tostring(L, i);

    if (!s) continue;
    switch (*s) {
    case 'c':  /* CAR/CTS */
      flags |= (s[1] == 'a') ? TIOCM_CAR : TIOCM_CTS;
      break;
    case 'd':  /* DSR */
      flags |= TIOCM_DSR;
      break;
    case 'r':  /* RING */
      flags |= TIOCM_RNG;
      break;
    }
  }

  sys_vm_leave();
#ifndef _WIN32
  do {
#ifdef TIOCMIWAIT
    res = !(ioctl(fd, TIOCMIWAIT, flags) || ioctl(fd, TIOCMGET, &status));
#else
    while ((res = !ioctl(fd, TIOCMGET, &status)) && !(status & flags))
      usleep(10000);  /* 10 msec polling */
#endif
  } while (!res && sys_eintr());
#else
  res = SetCommMask(fd, flags) && WaitCommEvent(fd, &status, NULL);
#endif
  sys_vm_enter();

  if (res) {
    if (flags & TIOCM_CAR)
      lua_pushboolean(L, status & TIOCM_CAR);
    if (flags & TIOCM_CTS)
      lua_pushboolean(L, status & TIOCM_CTS);
    if (flags & TIOCM_DSR)
      lua_pushboolean(L, status & TIOCM_DSR);
    if (flags & TIOCM_RNG)
      lua_pushboolean(L, status & TIOCM_RNG);
    return narg - 1;
  }
  return sys_seterror(L, 0);
}
Example #25
0
/*
 * Arguments: path (string), [more_info (boolean)]
 * Returns: [is_directory (boolean), is_file (boolean),
 *	is_read (boolean), is_write (boolean), is_execute (boolean),
 *	[is_link (boolean), size (number),
 *	access_time (number), modify_time (number), create_time (number)]]
 */
static int
sys_stat (lua_State *L)
{
  const char *path = luaL_checkstring(L, 1);
  const int more_info = lua_toboolean(L, 2);
#ifndef _WIN32
  struct stat st;
#else
  struct _stat st;
#endif
  int res;

  sys_vm_leave(L);
#ifndef _WIN32
  res = stat(path, &st);
#else
  {
    void *os_path = utf8_to_filename(path);
    if (!os_path)
      return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

    res = is_WinNT ? _wstat(os_path, &st) : _stat(os_path, &st);

    free(os_path);
  }
#endif
  sys_vm_enter(L);

  if (!res) {
    /* is directory? */
    lua_pushboolean(L,
#ifndef _WIN32
     S_ISDIR(st.st_mode)
#else
     st.st_mode & _S_IFDIR
#endif
    );
    /* is regular file? */
    lua_pushboolean(L,
#ifndef _WIN32
     S_ISREG(st.st_mode)
#else
     st.st_mode & _S_IFREG
#endif
    );
    /* can anyone read from file? */
    lua_pushboolean(L,
#ifndef _WIN32
     st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)
#else
     st.st_mode & _S_IREAD
#endif
    );
    /* can anyone write to file? */
    lua_pushboolean(L,
#ifndef _WIN32
     st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)
#else
     st.st_mode & _S_IWRITE
#endif
    );
    /* can anyone execute the file? */
    lua_pushboolean(L,
#ifndef _WIN32
     st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)
#else
     st.st_mode & _S_IEXEC
#endif
    );
    if (more_info) {
      /* is link? */
#ifndef _WIN32
      lua_pushboolean(L, S_ISLNK(st.st_mode));
#else
      DWORD attr;
      {
        void *os_path = utf8_to_filename(path);
        if (!os_path)
          return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

        attr = is_WinNT
         ? GetFileAttributesW(os_path)
         : GetFileAttributesA(os_path);

        free(os_path);
      }
      lua_pushboolean(L,
       attr > 0 && (attr & FILE_ATTRIBUTE_REPARSE_POINT));
#endif
      lua_pushnumber(L, (lua_Number) st.st_size);  /* size in bytes */
      lua_pushnumber(L, (lua_Number) st.st_atime);  /* access time */
      lua_pushnumber(L, (lua_Number) st.st_mtime);  /* modification time */
      lua_pushnumber(L, (lua_Number) st.st_ctime);  /* creation time */
      return 10;
    }
    return 5;
  }
  return sys_seterror(L, 0);
}
Example #26
0
File: poll.c Project: ezdiy/luasys
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
    struct event *ev_ready;
    struct event **events = evq->events;
    struct pollfd *fdset = evq->fdset;
    const int npolls = evq->npolls;
    int i, nready;

    if (timeout != 0L) {
	timeout = timeout_get(evq->tq, timeout, evq->now);
	if (timeout == 0L) {
	    ev_ready = timeout_process(evq->tq, NULL, evq->now);
	    goto end;
	}
    }

    sys_vm_leave();
    nready = poll(fdset, npolls, (int) timeout);
    sys_vm_enter();

    evq->now = get_milliseconds();

    if (nready == -1)
	return (errno == EINTR) ? 0 : EVQ_FAILED;

    if (timeout != TIMEOUT_INFINITE) {
	if (!nready) {
	    ev_ready = !evq->tq ? NULL
	     : timeout_process(evq->tq, NULL, evq->now);
	    if (ev_ready) goto end;
	    return EVQ_TIMEOUT;
	}

	timeout = evq->now;
    }

    ev_ready = NULL;
    if (fdset[0].revents & POLLIN) {
	fdset[0].revents = 0;
	ev_ready = signal_process_interrupt(evq, ev_ready, timeout);
	--nready;
    }

    for (i = 1; i < npolls; i++) {
	const int revents = fdset[i].revents;
	struct event *ev;
	unsigned int res;

	if (!revents) continue;

	fdset[i].revents = 0;
	ev = events[i];

	res = EVENT_ACTIVE;
	if ((revents & POLLFD_READ) && (ev->flags & EVENT_READ))
	    res |= EVENT_READ_RES;
	if ((revents & POLLFD_WRITE) && (ev->flags & EVENT_WRITE))
	    res |= EVENT_WRITE_RES;
	if (revents & POLLHUP)
	    res |= EVENT_EOF_RES;

	ev->flags |= res;
	if (ev->flags & EVENT_ONESHOT)
	    evq_del(ev, 1);
	else if (ev->tq && !(ev->flags & EVENT_TIMEOUT_MANUAL))
	    timeout_reset(ev, timeout);

	ev->next_ready = ev_ready;
	ev_ready = ev;

	if (!--nready) break;
    }
    if (!ev_ready) return 0;
 end:
    evq->ev_ready = ev_ready;
    return 0;
}
Example #27
0
/*
 * Arguments: host_name (string), [binary_addresses (table)]
 * Returns: [binary_addresses (table) | binary_address (string),
 *	canon_name (string)]
 */
static int
sock_getaddrinfo (lua_State *L)
{
  const char *host = luaL_checkstring(L, 1);
  int gai_errno;

#ifdef USE_GAI
  struct addrinfo hints, *result;

  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_UNSPEC;
  hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;

  sys_vm_leave(L);
  gai_errno = getaddrinfo(host, NULL, &hints, &result);
  sys_vm_enter(L);

  if (gai_errno) goto err;

  lua_settop(L, 2);
  if (!lua_istable(L, 2))
    sock_pushaddr(L, (struct sock_addr *) result->ai_addr);
  else {
    struct addrinfo *rp = result;
    int i;

    for (i = 1; rp; ++i, rp = rp->ai_next) {
      sock_pushaddr(L, (struct sock_addr *) rp->ai_addr);
      lua_rawseti(L, 2, i);
    }
  }
  lua_pushstring(L, result->ai_canonname);
  freeaddrinfo(result);
#else
  struct hostent *hp;

  sys_vm_leave(L);
  hp = gethostbyname(host);
  sys_vm_enter(L);

  if (!hp) {
    gai_errno = h_errno;
    goto err;
  }

  lua_settop(L, 2);
  if (!lua_istable(L, 2))
    lua_pushlstring(L, (char *) *hp->h_addr_list,
     sizeof(struct in_addr));
  else {
    const char **ap = hp->h_addr_list;
    int i;

    for (i = 1; *ap; ++i, ++ap) {
      lua_pushlstring(L, *ap, sizeof(struct in_addr));
      lua_rawseti(L, 2, i);
    }
  }
  lua_pushstring(L, hp->h_name);
#endif
  return 2;
 err:
  return sock_gai_seterror(L, gai_errno);
}
Example #28
0
/*
 * Arguments: membuf_udata, fd_udata, [protection (string: "rw"),
 *	offset (number), num_bytes (number), private/shared (boolean)]
 * Returns: [membuf_udata]
 */
static int
mem_map (lua_State *L)
{
    struct membuf *mb = checkudata(L, 1, MEM_TYPENAME);
    const fd_t *fdp = checkudata(L, 2, FD_TYPENAME);
    fd_t fd = fdp ? (fd_t) *fdp : (fd_t) -1;  /* named or anonymous mapping */
    const char *protstr = lua_tostring(L, 3);
    const lua_Number offset = lua_tonumber(L, 4);
    const int64_t off = (int64_t) offset;  /* to avoid warning */
    size_t len = (size_t) lua_tointeger(L, 5);
    const int is_private = lua_isboolean(L, -1) && lua_toboolean(L, -1);
    int prot = 0, flags;
    void *ptr;

#ifndef _WIN32
#ifndef MAP_ANON
    int is_anon = 0;
#endif

    sys_vm_leave();
    /* length */
    if (!len) {
	struct stat sb;
	if (fd == -1 || fstat(fd, &sb) == -1)
	    goto err;
	sb.st_size -= off;
	len = ((uint64_t) sb.st_size < (uint64_t) ~((size_t) 0))
	 ? (size_t) sb.st_size : ~((size_t) 0);
    }
    /* protection and flags */
    prot = PROT_READ;
    if (protstr) {
	if (protstr[0] == 'w')
	    prot = PROT_WRITE;
	else if (protstr[1] == 'w')
	    prot |= PROT_WRITE;
    }
    flags = is_private ? MAP_PRIVATE : MAP_SHARED;
    /* anonymous shared memory? */
    if (fd == -1) {
#ifdef MAP_ANON
	flags |= MAP_ANON;
#else
	if ((fd = open("/dev/zero", O_RDWR)) == -1)
	    goto err;
	is_anon = 1;
#endif
    }
    /* map file to memory */
    ptr = mmap(0, len, prot, flags, (int) fd, off);
#ifndef MAP_ANON
    if (is_anon) close(fd);
#endif
    if (ptr == MAP_FAILED) goto err;

#else
    sys_vm_leave();
    /* length */
    if (!len) {
	DWORD size_hi, size_lo;
	int64_t size;

	if (fd == (fd_t) -1) goto err;
	size_lo = GetFileSize(fd, &size_hi);
	if (size_lo == (DWORD) -1L && SYS_ERRNO != NO_ERROR)
	    goto err;
	size = INT64_MAKE(size_lo, size_hi) - off;
	len = ((uint64_t) size < (uint64_t) ~((DWORD) 0))
	 ? (DWORD) size : ~((DWORD) 0);
    }
    /* protection and flags */
    if (protstr && (protstr[0] == 'w' || protstr[1] == 'w')) {
	prot = PAGE_READWRITE;
	flags = FILE_MAP_WRITE;
    } else {
	prot = PAGE_READONLY;
	flags = FILE_MAP_READ;
    }
    if (is_private) {
	prot = PAGE_WRITECOPY;
	flags = FILE_MAP_COPY;
    }
    /* map file to memory */
    {
	const DWORD off_hi = INT64_HIGH(off);
	const DWORD off_lo = INT64_LOW(off);
	HANDLE hmap = CreateFileMapping(fd, NULL, prot, 0, len, NULL);

	if (!hmap) goto err;
	ptr = MapViewOfFile(hmap, flags, off_hi, off_lo, len);
	CloseHandle(hmap);
	if (!ptr) goto err;
    }
#endif /* !Win32 */
    sys_vm_enter();

    mb->flags |= MEM_MAP;
    mb->len = len;
    mb->data = ptr;
    lua_settop(L, 1);
    return 1;
 err:
    sys_vm_enter();
    return sys_seterror(L, 0);
}
Example #29
0
EVQ_API int
evq_wait (struct event_queue *evq, msec_t timeout)
{
    struct event *ev_ready = NULL;
    struct win32thr *wth = &evq->head;
    struct win32thr *threads = wth->next;
    CRITICAL_SECTION *head_cs = &wth->cs;
    HANDLE head_signal = wth->signal;
    int n = wth->n;
    int sig_ready = 0;
    DWORD wait_res;

    if (threads && win32thr_poll(evq) && evq_is_empty(evq))
	return 0;

    if (timeout != 0L) {
	timeout = timeout_get(wth->tq, timeout, evq->now);
	if (timeout == 0L) {
	    ev_ready = timeout_process(wth->tq, NULL, evq->now);
	    goto end;
	}
    }

    if (is_WinNT) {
	if (!iocp_is_empty(evq))
	    ev_ready = win32iocp_process(evq, NULL, 0L);

	if (ev_ready) {
	    evq->ev_ready = ev_ready;
	    timeout = 0L;
	} else {
	    /* head_signal is resetted by IOCP WSARecv/WSASend */
	    EnterCriticalSection(head_cs);
	    if (evq->sig_ready)
		timeout = 0L;
	    LeaveCriticalSection(head_cs);
	}
    }

    sys_vm_leave();
    wait_res = MsgWaitForMultipleObjects(n + 1, wth->handles, FALSE, timeout,
     (evq->win_msg ? QS_ALLEVENTS : 0));
    sys_vm_enter();

    evq->now = sys_milliseconds();

    ev_ready = evq->ev_ready;

    if (wait_res == WAIT_TIMEOUT) {
	if (ev_ready) goto end;
	if (!wth->tq && !evq->sig_ready)
	    return EVQ_TIMEOUT;
    }
    if (wait_res == (DWORD) (WAIT_OBJECT_0 + n + 1)) {
	struct event *ev = evq->win_msg;
	if (ev && !(ev->flags & EVENT_ACTIVE)) {
	    ev->flags |= EVENT_ACTIVE;
	    ev->next_ready = ev_ready;
	    ev_ready = ev;
	}
	goto end;
    }
    if (wait_res == WAIT_FAILED)
	return EVQ_FAILED;

    timeout = evq->now;
    if (!iocp_is_empty(evq))
	ev_ready = win32iocp_process(evq, ev_ready, timeout);

    wth->idx = wait_res;

    if (threads) {
	EnterCriticalSection(head_cs);
	ResetEvent(head_signal);

	threads = evq->wth_ready;
	evq->wth_ready = NULL;

	sig_ready = evq->sig_ready;
	evq->sig_ready = 0;
	LeaveCriticalSection(head_cs);

	if (wait_res == (DWORD) (WAIT_OBJECT_0 + n))
	    wth = threads;
	else
	    wth->next_ready = threads;
    } else {
	wth->next_ready = NULL;

	if (evq->sig_ready) {
	    EnterCriticalSection(head_cs);
	    ResetEvent(head_signal);

	    sig_ready = evq->sig_ready;
	    evq->sig_ready = 0;
	    LeaveCriticalSection(head_cs);
	}
    }

    if (sig_ready)
	ev_ready = signal_process_interrupt(evq, sig_ready, ev_ready, timeout);

    for (; wth; wth = wth->next_ready) {
	HANDLE *hp;  /* event handles */
	const int idx = wth->idx;
	int i;

	wth->state = WTHR_SLEEP;

	if (wth->tq) {
	    if (idx == WAIT_TIMEOUT) {
		ev_ready = timeout_process(wth->tq, ev_ready, timeout);
		continue;
	    }
	}

	hp = &wth->handles[idx];
	n = wth->n;
	i = idx;
	if (i >= n) continue;  /* some events deleted? */

	/* Traverse array of events */
	for (; ; ) {
	    WSANETWORKEVENTS ne;
	    struct event *ev = wth->events[i];
	    const int ev_flags = ev->flags;
	    unsigned int res = 0;

	    if (!(ev_flags & EVENT_SOCKET)) {
		if (ev_flags & EVENT_PID) {
		    DWORD status;
		    GetExitCodeProcess(ev->fd, &status);
		    res = (status << EVENT_EOF_SHIFT_RES);
		} else
		    ResetEvent(ev->fd);  /* all events must be manual-reset */
		res |= EVENT_READ_RES;
	    } else if (!WSAEnumNetworkEvents((int) ev->fd, *hp, &ne)) {
		if ((ev_flags & EVENT_READ)
		 && (ne.lNetworkEvents & WFD_READ))
		    res = EVENT_READ_RES;
		if ((ev_flags & EVENT_WRITE)
		 && (ne.lNetworkEvents & WFD_WRITE))
		    res |= EVENT_WRITE_RES;
		if (ne.lNetworkEvents & FD_CLOSE)
		    res |= EVENT_EOF_RES;
	    }

	    if (res) {
		ev->flags |= EVENT_ACTIVE | res;
		ev->next_ready = ev_ready;
		ev_ready = ev;

		if (ev_flags & EVENT_ONESHOT) {
		    win32thr_del(wth, ev);
		    --i, --n, --hp;
		} else if (ev->tq && !(ev_flags & EVENT_TIMEOUT_MANUAL))
		    timeout_reset(ev, timeout);
	    }

	    /* skip inactive events */
	    do {
		if (++i == n)
		    goto end_thread;
	    } while (WaitForSingleObject(*(++hp), 0) != WAIT_OBJECT_0);
	}
 end_thread:
	((void) 0);  /* avoid warning */
    }

    /* always check window messages */
    {
	struct event *ev = evq->win_msg;

	if (ev && GetQueueStatus(QS_ALLEVENTS)) {
	    ev->next_ready = ev_ready;
	    ev_ready = ev;
	}
    }
    if (!ev_ready)
	return (wait_res == WAIT_TIMEOUT && !sig_ready)
	 ? EVQ_TIMEOUT : 0;
 end:
    evq->ev_ready = ev_ready;
    return 0;
}
Example #30
0
/*
 * Arguments: fd_udata, path (string), [mode (string: "r", "w", "rw"),
 *	permissions (number), options (string) ...]
 * Returns: [fd_udata]
 */
static int
sys_open (lua_State *L)
{
    fd_t fd, *fdp = checkudata(L, 1, FD_TYPENAME);
    const char *path = luaL_checkstring(L, 2);
    const char *mode = lua_tostring(L, 3);
#ifndef _WIN32
    mode_t perm = (mode_t) luaL_optinteger(L, 4, SYS_FILE_PERMISSIONS);
#else
    int append = 0;
#endif
    int flags = O_RDONLY, i;

#undef OPT_START
#define OPT_START	5

    if (mode) {
	switch (mode[0]) {
	case 'w': flags = O_WRONLY; break;
	case 'r': if (mode[1] == 'w') flags = O_RDWR;
	}
    }
#ifndef _WIN32
    for (i = lua_gettop(L); i >= OPT_START; --i) {
	flags |= fdopt_flags[luaL_checkoption(L, i, NULL, fdopt_names)];
    }

    sys_vm_leave();
    fd = open(path, flags, perm);
    sys_vm_enter();
#else
    {
	DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
	DWORD creation = OPEN_EXISTING;
	DWORD attr = FILE_ATTRIBUTE_NORMAL
	 | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION;

	for (i = lua_gettop(L); i >= OPT_START; --i) {
	    const char *opt = lua_tostring(L, i);
	    if (opt)
		switch (opt[0]) {
		case 'a':	/* append */
		    append = 1;
		    break;
		case 'c':	/* creat */
		    creation &= ~OPEN_EXISTING;
		    creation |= CREATE_ALWAYS;
		    break;
		case 'e':	/* excl */
		    share = 0;
		    break;
		case 'r':	/* random */
		    attr |= FILE_FLAG_RANDOM_ACCESS;
		    break;
		case 's':	/* sync */
		    attr |= FILE_FLAG_WRITE_THROUGH;
		    break;
		case 't':	/* trunc */
		    creation &= ~OPEN_EXISTING;
		    creation |= TRUNCATE_EXISTING;
		    break;
		}
	}

	{
	    void *os_path = utf8_to_filename(path);
	    if (!os_path)
		return sys_seterror(L, ERROR_NOT_ENOUGH_MEMORY);

	    sys_vm_leave();
	    fd = is_WinNT
	     ? CreateFileW(os_path, flags, share, NULL, creation, attr, NULL)
	     : CreateFileA(os_path, flags, share, NULL, creation, attr, NULL);

	    free(os_path);
	    sys_vm_enter();
	}
    }
#endif
    if (fd != (fd_t) -1) {
	*fdp = fd;
#ifdef _WIN32
	if (append) {
	    LONG off_hi = 0L;
	    SetFilePointer(fd, 0L, &off_hi, SEEK_END);
	}
#endif
	lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}