/* copy a file from one to another. */ void MVM_file_copy(MVMThreadContext *tc, MVMString *src, MVMString *dest) { uv_fs_t req; char * const a = MVM_string_utf8_encode_C_string(tc, src); const uv_file in_fd = uv_fs_open(tc->loop, &req, (const char *)a, O_RDONLY, 0, NULL); if (in_fd >= 0 && uv_fs_stat(tc->loop, &req, a, NULL) >= 0) { char * const b = MVM_string_utf8_encode_C_string(tc, dest); const uv_file out_fd = uv_fs_open(tc->loop, &req, (const char *)b, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_MODE, NULL); MVM_free(a); if (out_fd >= 0 && uv_fs_sendfile(tc->loop, &req, out_fd, in_fd, 0, req.statbuf.st_size, NULL) >= 0) { MVM_free(b); if (uv_fs_close(tc->loop, &req, in_fd, NULL) < 0) { uv_fs_close(tc->loop, &req, out_fd, NULL); /* should close out_fd before throw. */ MVM_exception_throw_adhoc(tc, "Failed to close file: %s", uv_strerror(req.result)); } if (uv_fs_close(tc->loop, &req, out_fd, NULL) < 0) { MVM_exception_throw_adhoc(tc, "Failed to close file: %s", uv_strerror(req.result)); } return; } else MVM_free(b); } else MVM_free(a); MVM_exception_throw_adhoc(tc, "Failed to copy file: %s", uv_strerror(req.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_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; }
/* Dumps the statistics associated with a particular callsite object. */ void dump_stats_by_callsite(MVMThreadContext *tc, DumpStr *ds, MVMSpeshStatsByCallsite *css) { MVMuint32 i, j, k; if (css->cs) dump_callsite(tc, ds, css->cs); else append(ds, "No interned callsite\n"); appendf(ds, " Callsite hits: %d\n\n", css->hits); if (css->osr_hits) appendf(ds, " OSR hits: %d\n\n", css->osr_hits); appendf(ds, " Maximum stack depth: %d\n\n", css->max_depth); for (i = 0; i < css->num_by_type; i++) { MVMSpeshStatsByType *tss = &(css->by_type[i]); appendf(ds, " Type tuple %d\n", i); dump_stats_type_tuple(tc, ds, css->cs, tss->arg_types, " "); appendf(ds, " Hits: %d\n", tss->hits); if (tss->osr_hits) appendf(ds, " OSR hits: %d\n", tss->osr_hits); appendf(ds, " Maximum stack depth: %d\n", tss->max_depth); if (tss->num_by_offset) { append(ds, " Logged at offset:\n"); for (j = 0; j < tss->num_by_offset; j++) { MVMSpeshStatsByOffset *oss = &(tss->by_offset[j]); appendf(ds, " %d:\n", oss->bytecode_offset); for (k = 0; k < oss->num_types; k++) appendf(ds, " %d x type %s (%s)\n", oss->types[k].count, MVM_6model_get_stable_debug_name(tc, oss->types[k].type->st), (oss->types[k].type_concrete ? "Conc" : "TypeObj")); for (k = 0; k < oss->num_invokes; k++) { char *body_name = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.name); char *body_cuuid = MVM_string_utf8_encode_C_string(tc, oss->invokes[k].sf->body.cuuid); appendf(ds, " %d x static frame '%s' (%s) (caller is outer: %d, multi %d)\n", oss->invokes[k].count, body_name, body_cuuid, oss->invokes[k].caller_is_outer_count, oss->invokes[k].was_multi_count); MVM_free(body_name); MVM_free(body_cuuid); } for (k = 0; k < oss->num_type_tuples; k++) { appendf(ds, " %d x type tuple:\n", oss->type_tuples[k].count); dump_stats_type_tuple(tc, ds, oss->type_tuples[k].cs, oss->type_tuples[k].arg_types, " "); } for (k = 0; k < oss->num_plugin_guards; k++) appendf(ds, " %d x spesh plugin guard index %d\n", oss->plugin_guards[k].count, oss->plugin_guards[k].guard_index); } } append(ds, "\n"); } }
static MVMint32 find_deopt_target(MVMThreadContext *tc, MVMFrame *f, MVMint32 deopt_offset) { MVMint32 i; for (i = 0; i < f->spesh_cand->num_deopts * 2; i += 2) { if (f->spesh_cand->deopts[i + 1] == deopt_offset) { return f->spesh_cand->deopts[i]; } } MVM_oops(tc, "find_deopt_target failed for %s (%s)", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); }
/* Locates a method by name. Returns the method if it exists, or throws an * exception if it can not be found. */ void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { MVMObject *cache, *HOW, *find_method, *code; if (MVM_is_null(tc, obj)) MVM_exception_throw_adhoc(tc, "Cannot call method '%s' on a null object", MVM_string_utf8_encode_C_string(tc, name)); /* First try to find it in the cache. If we find it, we have a result. * If we don't find it, but the cache is authoritative, then error. */ cache = STABLE(obj)->method_cache; if (cache && IS_CONCRETE(cache)) { MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); if (!MVM_is_null(tc, meth)) { res->o = meth; return; } if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { MVMObject *handler = MVM_hll_current(tc)->method_not_found_error; if (!MVM_is_null(tc, handler)) { handler = MVM_frame_find_invokee(tc, handler, NULL); MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, &mnfe_callsite); tc->cur_frame->args[0].o = obj; tc->cur_frame->args[1].s = name; STABLE(handler)->invoke(tc, handler, &mnfe_callsite, tc->cur_frame->args); return; } else { MVM_exception_throw_adhoc(tc, "Cannot find method '%s'", MVM_string_utf8_encode_C_string(tc, name)); } } } /* Otherwise, need to call the find_method method. We make the assumption * that the invocant's meta-object's type is composed. */ HOW = STABLE(obj)->HOW; find_method = MVM_6model_find_method_cache_only(tc, HOW, tc->instance->str_consts.find_method); if (MVM_is_null(tc, find_method)) MVM_exception_throw_adhoc(tc, "Cannot find method '%s': no method cache and no .^find_method", MVM_string_utf8_encode_C_string(tc, name)); /* Set up the call, using the result register as the target. */ code = MVM_frame_find_invokee(tc, find_method, NULL); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, &fm_callsite); tc->cur_frame->args[0].o = HOW; tc->cur_frame->args[1].o = obj; tc->cur_frame->args[2].s = name; STABLE(code)->invoke(tc, code, &fm_callsite, tc->cur_frame->args); }
/* De-optimizes the current frame by directly specifying the addresses */ void MVM_spesh_deopt_one_direct(MVMThreadContext *tc, MVMint32 deopt_offset, MVMint32 deopt_target) { MVMFrame *f = tc->cur_frame; if (f->effective_bytecode != f->static_info->body.bytecode) { deopt_frame(tc, tc->cur_frame, deopt_offset, deopt_target); } else { MVM_exception_throw_adhoc(tc, "deopt_one_direct failed for %s (%s)", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); } }
void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { MVMObject *cache, *HOW, *find_method, *code; MVMCallsite *findmeth_callsite; if (MVM_is_null(tc, obj)) MVM_exception_throw_adhoc(tc, "Cannot call method '%s' on a null object", MVM_string_utf8_encode_C_string(tc, name)); /* First try to find it in the cache. If we find it, we have a result. * If we don't find it, but the cache is authoritative, then error. */ cache = get_method_cache(tc, STABLE(obj)); if (cache && IS_CONCRETE(cache)) { MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); if (!MVM_is_null(tc, meth)) { res->o = meth; return; } if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { die_over_missing_method(tc, obj, name); return; } } /* Otherwise, need to call the find_method method. We make the assumption * that the invocant's meta-object's type is composed. */ HOW = MVM_6model_get_how(tc, STABLE(obj)); find_method = MVM_6model_find_method_cache_only(tc, HOW, tc->instance->str_consts.find_method); if (MVM_is_null(tc, find_method)) MVM_exception_throw_adhoc(tc, "Cannot find method '%s': no method cache and no .^find_method", MVM_string_utf8_encode_C_string(tc, name)); /* Set up the call, using the result register as the target. */ code = MVM_frame_find_invokee(tc, find_method, NULL); findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD); MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite); { FindMethodSRData *fm = MVM_malloc(sizeof(FindMethodSRData)); fm->obj = obj; fm->name = name; fm->res = res; tc->cur_frame->special_return = late_bound_find_method_return; tc->cur_frame->special_return_data = fm; tc->cur_frame->mark_special_return_data = mark_find_method_sr_data; } tc->cur_frame->args[0].o = HOW; tc->cur_frame->args[1].o = obj; tc->cur_frame->args[2].s = name; STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args); }
/* De-optimizes the current frame by directly specifying the addresses */ void MVM_spesh_deopt_one_direct(MVMThreadContext *tc, MVMint32 deopt_offset, MVMint32 deopt_target) { MVMFrame *f = tc->cur_frame; if (tc->instance->profiling) MVM_profiler_log_deopt_one(tc); if (f->effective_bytecode != f->static_info->body.bytecode) { deopt_frame(tc, tc->cur_frame, deopt_offset, deopt_target); } else { MVM_oops(tc, "deopt_one_direct failed for %s (%s)", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); } }
/* rename one file to another. */ void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest) { char * const a = MVM_string_utf8_encode_C_string(tc, src); char * const b = MVM_string_utf8_encode_C_string(tc, dest); uv_fs_t req; if(uv_fs_rename(tc->loop, &req, a, b, NULL) < 0 ) { MVM_free(a); MVM_free(b); MVM_exception_throw_adhoc(tc, "Failed to rename file: %s", uv_strerror(req.result)); } MVM_free(a); MVM_free(b); }
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env) { MVMint64 result = 0, spawn_result = 0; uv_process_t *process = calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; { MVMint64 len = strlen(cmdin); MVMint64 i; for (i = 0; i < len; i++) if (cmdin[i] == '/') cmdin[i] = '\\'; } args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); SPAWN(_cmd); FREE_ENV(); free(_cwd); #ifdef _WIN32 free(_cmd); #endif free(cmdin); return result; }
/* open a filehandle; takes a type object */ MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) { MVMOSHandle *result; apr_status_t rv; apr_pool_t *tmp_pool; apr_file_t *file_handle; apr_int32_t flag; MVMObject *type_object = tc->instance->boot_types->BOOTIO; char *fname = MVM_string_utf8_encode_C_string(tc, filename); char *fmode; /* need a temporary pool */ if ((rv = apr_pool_create(&tmp_pool, POOL(tc))) != APR_SUCCESS) { free(fname); MVM_exception_throw_apr_error(tc, rv, "Open file failed to create pool: "); } fmode = MVM_string_utf8_encode_C_string(tc, mode); /* generate apr compatible open mode flags */ if (0 == strcmp("r", fmode)) flag = APR_FOPEN_READ; else if (0 == strcmp("w", fmode)) flag = APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE; else if (0 == strcmp("wa", fmode)) flag = APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_APPEND; else MVM_exception_throw_adhoc(tc, "invalid open mode: %d", fmode); /* try to open the file */ if ((rv = apr_file_open(&file_handle, (const char *)fname, flag, APR_OS_DEFAULT, tmp_pool)) != APR_SUCCESS) { free(fname); free(fmode); apr_pool_destroy(tmp_pool); MVM_exception_throw_apr_error(tc, rv, "Failed to open file: "); } /* initialize the object */ result = (MVMOSHandle *)REPR(type_object)->allocate(tc, STABLE(type_object)); result->body.file_handle = file_handle; result->body.handle_type = MVM_OSHANDLE_FILE; result->body.mem_pool = tmp_pool; result->body.encoding_type = MVM_encoding_type_utf8; free(fname); free(fmode); return (MVMObject *)result; }
/* De-optimizes the currently executing frame, provided it is specialized and * at a valid de-optimization point. Typically used when a guard fails. */ void MVM_spesh_deopt_one(MVMThreadContext *tc) { MVMFrame *f = tc->cur_frame; /*fprintf(stderr, "deopt_one requested in frame '%s' (cuid '%s')\n", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid));*/ if (f->effective_bytecode != f->static_info->body.bytecode) { MVMint32 deopt_offset = *(tc->interp_cur_op) - f->effective_bytecode; MVMint32 deopt_target = find_deopt_target(tc, f, deopt_offset); deopt_frame(tc, tc->cur_frame, deopt_offset, deopt_target); } else { MVM_exception_throw_adhoc(tc, "deopt_one failed for %s (%s)", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); } }
static apr_finfo_t MVM_file_info(MVMThreadContext *tc, MVMString *filename, apr_int32_t wanted) { apr_status_t rv; apr_pool_t *tmp_pool; apr_file_t *file_handle; apr_finfo_t finfo; char *fname = MVM_string_utf8_encode_C_string(tc, filename); /* need a temporary pool */ if ((rv = apr_pool_create(&tmp_pool, POOL(tc))) != APR_SUCCESS) { free(fname); MVM_exception_throw_apr_error(tc, rv, "Open file failed to create pool: "); } if ((rv = apr_file_open(&file_handle, (const char *)fname, APR_FOPEN_READ, APR_OS_DEFAULT, tmp_pool)) != APR_SUCCESS) { free(fname); apr_pool_destroy(tmp_pool); MVM_exception_throw_apr_error(tc, rv, "Failed to open file: "); } free(fname); if((rv = apr_file_info_get(&finfo, wanted, file_handle)) != APR_SUCCESS) { MVM_exception_throw_apr_error(tc, rv, "Failed to stat file: "); } if ((rv = apr_file_close(file_handle)) != APR_SUCCESS) { MVM_exception_throw_apr_error(tc, rv, "Failed to close filehandle: "); } return finfo; }
static void dump_callsite(MVMThreadContext *tc, DumpStr *ds, MVMCallsite *cs) { MVMuint16 i; appendf(ds, "Callsite %p (%d args, %d pos)\n", cs, cs->arg_count, cs->num_pos); for (i = 0; i < (cs->arg_count - cs->num_pos) / 2; i++) { if (cs->arg_names[i]) { char * argname_utf8 = MVM_string_utf8_encode_C_string(tc, cs->arg_names[i]); appendf(ds, " - %s\n", argname_utf8); MVM_free(argname_utf8); } } if (cs->num_pos) append(ds, "Positional flags: "); for (i = 0; i < cs->num_pos; i++) { MVMCallsiteEntry arg_flag = cs->arg_flags[i]; if (i) append(ds, ", "); if (arg_flag == MVM_CALLSITE_ARG_OBJ) { append(ds, "obj"); } else if (arg_flag == MVM_CALLSITE_ARG_INT) { append(ds, "int"); } else if (arg_flag == MVM_CALLSITE_ARG_NUM) { append(ds, "num"); } else if (arg_flag == MVM_CALLSITE_ARG_STR) { append(ds, "str"); } } if (cs->num_pos) append(ds, "\n"); append(ds, "\n"); }
/* Actually, it may return sockaddr_in6 as well; it's not a problem for us, because we just * pass is straight to uv, and the first thing it does is it looks at the address family, * but it's a thing to remember if someone feels like peeking inside the returned struct. */ 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; struct addrinfo *result; int error; char port_cstr[8]; snprintf(port_cstr, 8, "%d", (int)port); error = getaddrinfo(host_cstr, port_cstr, NULL, &result); MVM_free(host_cstr); if (error == 0) { if (result->ai_addr->sa_family == AF_INET6) { dest = MVM_malloc(sizeof(struct sockaddr_in6)); memcpy(dest, result->ai_addr, sizeof(struct sockaddr_in6)); } else { dest = MVM_malloc(sizeof(struct sockaddr)); memcpy(dest, result->ai_addr, sizeof(struct sockaddr)); } } else { MVM_exception_throw_adhoc(tc, "Failed to resolve host name"); } freeaddrinfo(result); return dest; }
/* gets environment variable value */ MVMString * MVM_proc_getenv(MVMThreadContext *tc, MVMString *var) { MVMString *result; apr_status_t rv; char *varstring = MVM_string_utf8_encode_C_string(tc, var); char *value; apr_pool_t *tmp_pool; /* need a temporary pool */ if ((rv = apr_pool_create(&tmp_pool, POOL(tc))) != APR_SUCCESS) { free(varstring); apr_pool_destroy(tmp_pool); MVM_exception_throw_apr_error(tc, rv, "Failed to get env variable: "); } if ((rv = apr_env_get(&value, (const char *)varstring, tmp_pool)) != APR_SUCCESS && rv != 2) { free(varstring); apr_pool_destroy(tmp_pool); MVM_exception_throw_apr_error(tc, rv, "Failed to get env variable: "); } /* TODO find out the define for the magic value 2 (env var not found) */ result = MVM_string_utf8_decode(tc, tc->instance->VMString, rv == 2 ? "" : value, rv == 2 ? 0 : strlen(value)); free(varstring); apr_pool_destroy(tmp_pool); return result; }
MVMint64 MVM_file_isexecutable(MVMThreadContext *tc, MVMString *filename, MVMint32 use_lstat) { if (!MVM_file_exists(tc, filename, use_lstat)) return 0; else { MVMint64 r = 0; uv_stat_t statbuf = file_info(tc, filename, use_lstat); if ((statbuf.st_mode & S_IFMT) == S_IFDIR) return 1; else { // true if fileext is in PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC MVMString *dot = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "."); MVMROOT(tc, dot, { MVMint64 n = MVM_string_index_from_end(tc, filename, dot, 0); if (n >= 0) { MVMString *fileext = MVM_string_substring(tc, filename, n, -1); char *ext = MVM_string_utf8_encode_C_string(tc, fileext); char *pext = getenv("PATHEXT"); int plen = strlen(pext); int i; for (i = 0; i < plen; i++) { if (0 == stricmp(ext, pext++)) { r = 1; break; } } MVM_free(ext); MVM_free(pext); } }); } return r; }
MVM_STATIC_INLINE const MVMOpInfo * get_info(Validator *val, MVMuint16 opcode) { const MVMOpInfo *info; if (opcode < MVM_OP_EXT_BASE) { info = MVM_op_get_op(opcode); if (!info) fail(val, MSG(val, "invalid opcode %u"), opcode); } else { MVMuint16 index = opcode - MVM_OP_EXT_BASE; MVMExtOpRecord *record; if (index >= val->cu->body.num_extops) fail(val, MSG(val, "invalid extension opcode %u - should be less than %u"), opcode, MVM_OP_EXT_BASE + val->cu->body.num_extops); record = &val->cu->body.extops[index]; info = MVM_ext_resolve_extop_record(val->tc, record); if (!info) fail(val, MSG(val, "extension op '%s' not registered"), MVM_string_utf8_encode_C_string(val->tc, record->name)); } return info; }
/* 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; }
/* Change directory. */ void MVM_dir_chdir(MVMThreadContext *tc, MVMString *dir) { char * const dirstring = MVM_string_utf8_encode_C_string(tc, dir); if (uv_chdir((const char *)dirstring) != 0) { MVM_free(dirstring); MVM_exception_throw_adhoc(tc, "chdir failed: %s", uv_strerror(errno)); } MVM_free(dirstring); }
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env) { MVMint64 result, spawn_result; uv_process_t process = {0}; uv_process_options_t process_options = {0}; int i; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif MVMROOT(tc, iter, { MVMString * const equal = MVM_string_ascii_decode(tc, tc->instance->VMString, STR_WITH_LEN("=")); MVMROOT(tc, equal, { MVMString *env_str; i = 0; while(MVM_iter_istrue(tc, iter)) { MVM_repr_shift_o(tc, (MVMObject *)iter); env_str = MVM_string_concatenate(tc, MVM_iterkey_s(tc, iter), equal); env_str = MVM_string_concatenate(tc, env_str, MVM_repr_get_str(tc, MVM_iterval(tc, iter))); _env[i++] = MVM_string_utf8_encode_C_string(tc, env_str); } _env[size] = NULL; }); });
/* Get a representation's ID from its name. Note that the IDs may change so * it's best not to store references to them in e.g. the bytecode stream. */ MVMuint32 MVM_repr_name_to_id(MVMThreadContext *tc, MVMString *name) { MVMREPRHashEntry *entry; MVM_string_flatten(tc, name); MVM_HASH_GET(tc, tc->instance->repr_name_to_id_hash, name, entry) if (entry == NULL) MVM_exception_throw_adhoc(tc, "Lookup by name of unknown REPR: %s", MVM_string_utf8_encode_C_string(tc, name)); return entry->value; }
/* Panic over an unhandled exception object. */ static void panic_unhandled_ex(MVMThreadContext *tc, MVMException *ex) { /* If there's no message, fall back to category. */ if (!ex->body.message) panic_unhandled_cat(tc, ex->body.category); /* Otherwise, dump message and a backtrace. */ fprintf(stderr, "Unhandled exception: %s\n", MVM_string_utf8_encode_C_string(tc, ex->body.message)); dump_backtrace(tc); exit(1); }
void MVM_file_chmod(MVMThreadContext *tc, MVMString *f, MVMint64 flag) { char * const a = MVM_string_utf8_encode_C_string(tc, f); uv_fs_t req; if(uv_fs_chmod(tc->loop, &req, a, flag, NULL) < 0 ) { MVM_free(a); MVM_exception_throw_adhoc(tc, "Failed to set permissions on path: %s", uv_strerror(req.result)); } MVM_free(a); }
/* Remove a directory recursively. */ void MVM_dir_rmdir(MVMThreadContext *tc, MVMString *path) { char * const pathname = MVM_string_utf8_encode_C_string(tc, path); uv_fs_t req; if(uv_fs_rmdir(tc->loop, &req, pathname, NULL) < 0 ) { MVM_free(pathname); MVM_exception_throw_adhoc(tc, "Failed to rmdir: %s", uv_strerror(req.result)); } MVM_free(pathname); }
/* 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; } }
MVMint64 MVM_file_exists(MVMThreadContext *tc, MVMString *f, MVMint32 use_lstat) { uv_fs_t req; char * const a = MVM_string_utf8_encode_C_string(tc, f); const MVMint64 result = (use_lstat ? uv_fs_lstat(tc->loop, &req, a, NULL) : uv_fs_stat(tc->loop, &req, a, NULL) ) < 0 ? 0 : 1; MVM_free(a); return result; }
/* rename one file to another. */ void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest) { apr_status_t rv; char *a, *b, *afull, *bfull; MVMuint32 len; apr_pool_t *tmp_pool; /* need a temporary pool */ if ((rv = apr_pool_create(&tmp_pool, POOL(tc))) != APR_SUCCESS) { MVM_exception_throw_apr_error(tc, rv, "Failed to rename file: "); } afull = MVM_file_get_full_path(tc, tmp_pool, a = MVM_string_utf8_encode_C_string(tc, src)); bfull = MVM_file_get_full_path(tc, tmp_pool, b = MVM_string_utf8_encode_C_string(tc, dest)); free(a); free(b); if ((rv = apr_file_rename((const char *)afull, (const char *)bfull, tmp_pool)) != APR_SUCCESS) { apr_pool_destroy(tmp_pool); MVM_exception_throw_apr_error(tc, rv, "Failed to rename file: "); } apr_pool_destroy(tmp_pool); }
/* set permissions. see * http://apr.apache.org/docs/apr/1.4/group__apr__file__permissions.html * XXX TODO: accept bits by perl format instead...? */ void MVM_file_chmod(MVMThreadContext *tc, MVMString *f, MVMint64 flag) { apr_status_t rv; char *a; a = MVM_string_utf8_encode_C_string(tc, f); if ((rv = apr_file_perms_set((const char *)a, (apr_fileperms_t)flag)) != APR_SUCCESS) { free(a); MVM_exception_throw_apr_error(tc, rv, "Failed to set permissions on path: "); } free(a); }
char * MVM_exception_backtrace_line(MVMThreadContext *tc, MVMFrame *cur_frame, MVMuint16 not_top) { MVMString *filename = cur_frame->static_info->body.cu->body.filename; MVMString *name = cur_frame->static_info->body.name; /* XXX TODO: make the caller pass in a char ** and a length pointer so * we can update it if necessary, and the caller can cache it. */ char *o = MVM_malloc(1024); MVMuint8 *cur_op = not_top ? cur_frame->return_address : cur_frame->throw_address; MVMuint32 offset = cur_op - cur_frame->effective_bytecode; MVMuint32 instr = MVM_bytecode_offset_to_instr_idx(tc, cur_frame->static_info, offset); MVMBytecodeAnnotation *annot = MVM_bytecode_resolve_annotation(tc, &cur_frame->static_info->body, offset > 0 ? offset - 1 : 0); MVMuint32 line_number = annot ? annot->line_number : 1; MVMuint16 string_heap_index = annot ? annot->filename_string_heap_index : 0; char *tmp1 = annot && string_heap_index < cur_frame->static_info->body.cu->body.num_strings ? MVM_string_utf8_encode_C_string(tc, cur_frame->static_info->body.cu->body.strings[string_heap_index]) : NULL; /* We may be mid-instruction if exception was thrown at an unfortunate * point; try to cope with that. */ if (instr == MVM_BC_ILLEGAL_OFFSET && offset >= 2) instr = MVM_bytecode_offset_to_instr_idx(tc, cur_frame->static_info, offset - 2); snprintf(o, 1024, " %s %s:%u (%s:%s:%u)", not_top ? "from" : " at", tmp1 ? tmp1 : "<unknown>", line_number, filename ? MVM_string_utf8_encode_C_string(tc, filename) : "<ephemeral file>", name ? MVM_string_utf8_encode_C_string(tc, name) : "<anonymous frame>", instr ); if (tmp1) MVM_free(tmp1); if (annot) MVM_free(annot); return o; }