/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_encode_C_string(tc, filename); char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); uv_fs_t req; uv_file fd; /* Resolve mode description to flags. */ int flag; if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fmode, NULL }; MVM_free(fname); MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode: %s", fmode); } MVM_free(fmode); /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { char *waste[] = { fname, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, uv_strerror(req.result)); } /* Set up handle. */ data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename); int fd; int flag; STAT statbuf; /* Resolve mode description to flags. */ char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fname, fmode, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode for file %s: %s", fname, fmode); } MVM_free(fmode); /* Try to open the file. */ #ifdef _WIN32 flag |= _O_BINARY; #endif if ((fd = open((const char *)fname, flag, DEFAULT_MODE)) == -1) { char *waste[] = { fname, NULL }; const char *err = strerror(errno); MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err); } /* Check that we didn't open a directory by accident. If fstat fails, just move on: Most of the documented error cases should already have triggered when opening the file, and we can't do anything about the others; a failure also does not necessarily imply that the file descriptor cannot be used for reading/writing. */ if (fstat(fd, &statbuf) == 0 && (statbuf.st_mode & S_IFMT) == S_IFDIR) { char *waste[] = { fname, NULL }; if (close(fd) == -1) { const char *err = strerror(errno); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s", fname, err); } MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname); } /* Set up handle. */ MVM_free(fname); { MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); data->fd = fd; data->seekable = MVM_platform_lseek(fd, 0, SEEK_CUR) != -1; result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } }
/* This function may return any type of sockaddr e.g. sockaddr_un, sockaddr_in or sockaddr_in6 * It shouldn't be a problem with general code as long as the port number is kept below the int16 limit: 65536 * After this it defines the family which may spawn non internet sockaddr's * The family can be extracted by (port >> 16) & USHORT_MAX * * Currently supported families: * * AF_UNSPEC = 1 * Unspecified, in most cases should be equal to AF_INET or AF_INET6 * * AF_UNIX = 1 * Unix domain socket, will spawn a sockaddr_un which will use the given host as path * e.g: MVM_io_resolve_host_name(tc, "/run/moarvm.sock", 1 << 16) * will spawn an unix domain socket on /run/moarvm.sock * * AF_INET = 2 * IPv4 socket * * AF_INET6 = 10 * IPv6 socket */ struct sockaddr * MVM_io_resolve_host_name(MVMThreadContext *tc, MVMString *host, MVMint64 port) { char *host_cstr = MVM_string_utf8_encode_C_string(tc, host); struct sockaddr *dest; int error; struct addrinfo *result; char port_cstr[8]; unsigned short family = (port >> 16) & USHRT_MAX; struct addrinfo hints; #ifndef _WIN32 /* AF_UNIX = 1 */ if (family == AF_UNIX) { struct sockaddr_un *result_un = MVM_malloc(sizeof(struct sockaddr_un)); if (strlen(host_cstr) > 107) { MVM_free(result_un); MVM_free(host_cstr); MVM_exception_throw_adhoc(tc, "Socket path can only be maximal 107 characters long"); } result_un->sun_family = AF_UNIX; strcpy(result_un->sun_path, host_cstr); MVM_free(host_cstr); return (struct sockaddr *)result_un; } #endif hints.ai_family = family; hints.ai_socktype = 0; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_addr = NULL; hints.ai_canonname = NULL; hints.ai_next = NULL; snprintf(port_cstr, 8, "%d", (int)port); MVM_gc_mark_thread_blocked(tc); error = getaddrinfo(host_cstr, port_cstr, &hints, &result); MVM_gc_mark_thread_unblocked(tc); if (error == 0) { size_t size = get_struct_size_for_family(result->ai_addr->sa_family); MVM_free(host_cstr); dest = MVM_malloc(size); memcpy(dest, result->ai_addr, size); } else { char *waste[] = { host_cstr, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Failed to resolve host name '%s' with family %d. Error: '%s'", host_cstr, family, gai_strerror(error)); } freeaddrinfo(result); return dest; }
static MVMReprRegistry * find_repr_by_name(MVMThreadContext *tc, MVMString *name) { MVMReprRegistry *entry; MVM_HASH_GET(tc, tc->instance->repr_hash, name, entry) if (entry == NULL) { char *c_name = MVM_string_ascii_encode_any(tc, name); char *waste[] = { c_name, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Lookup by name of unknown REPR: %s", c_name); } return entry; }
/* Maps a calling convention name to an ID. */ MVMint16 MVM_nativecall_get_calling_convention(MVMThreadContext *tc, MVMString *name) { MVMint16 result = DC_CALL_C_DEFAULT; if (name && MVM_string_graphs(tc, name) > 0) { char *cname = MVM_string_utf8_encode_C_string(tc, name); if (strcmp(cname, "cdecl") == 0) result = DC_CALL_C_X86_CDECL; else if (strcmp(cname, "stdcall") == 0) result = DC_CALL_C_X86_WIN32_STD; else if (strcmp(cname, "stdcall") == 0) result = DC_CALL_C_X64_WIN64; else { char *waste[] = { cname, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Unknown calling convention '%s' used for native call", cname); } MVM_free(cname); } return result; }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename); uv_fs_t req; uv_file fd; int flag; /* Resolve mode description to flags. */ { char * const fmode = MVM_string_utf8_encode_C_string(tc, mode); if (!resolve_open_mode(&flag, fmode)) { char *waste[] = { fname, fmode, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode for file %s: %s", fname, fmode); } MVM_free(fmode); } /* Try to open the file. */ if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) { char *waste[] = { fname, NULL }; const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err); } uv_fs_req_cleanup(&req); /* Check that we didn't open a directory by accident. If fstat fails, just move on: Most of the documented error cases should already have triggered when opening the file, and we can't do anything about the others; a failure also does not necessarily imply that the file descriptor cannot be used for reading/writing. */ if (uv_fs_fstat(tc->loop, &req, fd, NULL) == 0 && (req.statbuf.st_mode & S_IFMT) == S_IFDIR) { char *waste[] = { fname, NULL }; uv_fs_req_cleanup(&req); if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) { const char *err = uv_strerror(req.result); uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s", fname, err); } uv_fs_req_cleanup(&req); MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname); } uv_fs_req_cleanup(&req); /* Set up handle. */ { MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); data->fd = fd; data->filename = fname; data->encoding = MVM_encoding_type_utf8; MVM_string_decode_stream_sep_default(tc, &(data->sep_spec)); result->body.ops = &op_table; result->body.data = data; return (MVMObject *)result; } }
MVM_NO_RETURN static void parse_error(MVMThreadContext *tc, MVMString *s, const char* reason) { char* got = MVM_string_utf8_c8_encode_C_string(tc, s); char *waste[] = { got, NULL }; MVM_exception_throw_adhoc_free(tc, waste, "Can't convert '%s' to num: %s", got, reason); }