/* * 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); }
/* * 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); }
/* * 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; }
/* * 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); }
/* * 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); }
/* * 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} };
/* * 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); }
/* * 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; }
/* * 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); }
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; }
/* * 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; }
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; }
/* * 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; }
/* * 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); }
/* * 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); }
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; }
/* * 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); }
/* * 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; }
/* * 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} };
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; }
/* * 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 } }
/* * 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); }
/* * 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; }
/* * 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); }
/* * 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); }
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; }
/* * 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); }
/* * 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); }
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; }
/* * 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); }