예제 #1
0
파일: argvenvp.c 프로젝트: neeraj9/sbox2
/* Exec preprocessor:
 * (previously known as "sb_execve_mod")
*/
int sb_execve_preprocess(char **file, char ***argv, char ***envp)
{
    struct lua_instance *luaif = get_lua();
    int res, new_argc, new_envc;

    if (!luaif) return(0);

    if (!argv || !envp) {
        SB_LOG(SB_LOGLEVEL_ERROR,
               "ERROR: sb_argvenvp: (argv || envp) == NULL");
        release_lua(luaif);
        return -1;
    }

    if (getenv("SBOX_DISABLE_ARGVENVP")) {
        SB_LOG(SB_LOGLEVEL_DEBUG, "sb_argvenvp disabled(E):");
        release_lua(luaif);
        return 0;
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_preprocess: gettop=%d", lua_gettop(luaif->lua));

    lua_getfield(luaif->lua, LUA_GLOBALSINDEX, "sbox_execve_preprocess");
    lua_pushstring(luaif->lua, *file);
    free(*file);

    strvec_to_lua_table(luaif, *argv);
    strvec_free(*argv);

    strvec_to_lua_table(luaif, *envp);
    strvec_free(*envp);

    /* args:    binaryname, argv, envp
     * returns: err, file, argc, argv, envc, envp */
    lua_call(luaif->lua, 3, 6);

    res = lua_tointeger(luaif->lua, -6);
    *file = strdup(lua_tostring(luaif->lua, -5));
    new_argc = lua_tointeger(luaif->lua, -4);
    new_envc = lua_tointeger(luaif->lua, -2);

    lua_string_table_to_strvec(luaif, -3, argv, new_argc);
    lua_string_table_to_strvec(luaif, -1, envp, new_envc);

    /* remove sbox_execve_preprocess' return values from the stack.  */
    lua_pop(luaif->lua, 6);

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_preprocess: at exit, gettop=%d", lua_gettop(luaif->lua));
    release_lua(luaif);
    return res;
}
예제 #2
0
파일: js_page.c 프로젝트: Bibamaru/showtime
static void
js_model_destroy(js_model_t *jm)
{
  assert(TAILQ_FIRST(&jm->jm_items) == NULL);

  if(jm->jm_args)
    strvec_free(jm->jm_args);

  prop_unsubscribe(jm->jm_eventsub);

  if(jm->jm_root)      prop_ref_dec(jm->jm_root);
  if(jm->jm_loading)   prop_ref_dec(jm->jm_loading);
  if(jm->jm_nodes)     prop_ref_dec(jm->jm_nodes);
  if(jm->jm_actions)   prop_ref_dec(jm->jm_actions);
  if(jm->jm_type)      prop_ref_dec(jm->jm_type);
  if(jm->jm_error)     prop_ref_dec(jm->jm_error);
  if(jm->jm_contents)  prop_ref_dec(jm->jm_contents);
  if(jm->jm_entries)   prop_ref_dec(jm->jm_entries);
  if(jm->jm_source)    prop_ref_dec(jm->jm_source);
  if(jm->jm_metadata)  prop_ref_dec(jm->jm_metadata);
  if(jm->jm_options)   prop_ref_dec(jm->jm_options);
  if(jm->jm_eventsink) prop_ref_dec(jm->jm_eventsink);

  if(jm->jm_pc != NULL)
    prop_courier_destroy(jm->jm_pc);
  free(jm->jm_url);
  hts_mutex_lock(&js_model_mutex);
  LIST_REMOVE(jm, jm_link);
  hts_mutex_unlock(&js_model_mutex);
  free(jm);
}
예제 #3
0
파일: luaif.c 프로젝트: OlegGirko/ldbox
/* Make preparations for an union directory:
 * (FIXME. This is not very efficient)
 * (FIXME. Does not remove removed entries)
 * (FIXME. add description)
 *
 * Parameters:
 * 1. Path to the directory, which is presented as
 *    union of more than one real directories
 * 2. Number of real directory paths
 * 3. Array of real directory paths
 * Returns:
 * 1. Status (boolean): false if error, true if ok
 * 2. Path to the created union directory.
*/
static int lua_lb_prep_union_dir(lua_State *l)
{
	char *dst_path = NULL;
	int num_real_dir_entries;
	char **src_paths = NULL;
	char *result_path = NULL;

	int n = lua_gettop(l);
	
	if (n == 3) {
		dst_path = strdup(lua_tostring(l, 1));
		num_real_dir_entries = lua_tointeger(l, 2);

		if (dst_path && (num_real_dir_entries > 0)) {
			lua_string_table_to_strvec(l, 3, &src_paths, num_real_dir_entries);
			result_path = prep_union_dir(dst_path, (const char **)src_paths, num_real_dir_entries);
			strvec_free(src_paths);
		}
	}
	lua_pushboolean(l, result_path ? 1 : 0);
	lua_pushstring(l, result_path);
	free(dst_path);
	if (result_path) free(result_path);
	return 2;
}
예제 #4
0
파일: js_page.c 프로젝트: Allba/showtime
static void
js_model_destroy(js_model_t *jm)
{
  if(jm->jm_args)
    strvec_free(jm->jm_args);

  prop_unsubscribe(jm->jm_eventsub);

  if(jm->jm_root)      prop_ref_dec(jm->jm_root);
  if(jm->jm_loading)   prop_ref_dec(jm->jm_loading);
  if(jm->jm_nodes)     prop_ref_dec(jm->jm_nodes);
  if(jm->jm_actions)   prop_ref_dec(jm->jm_actions);
  if(jm->jm_type)      prop_ref_dec(jm->jm_type);
  if(jm->jm_error)     prop_ref_dec(jm->jm_error);
  if(jm->jm_contents)  prop_ref_dec(jm->jm_contents);
  if(jm->jm_entries)   prop_ref_dec(jm->jm_entries);
  if(jm->jm_source)    prop_ref_dec(jm->jm_source);
  if(jm->jm_metadata)  prop_ref_dec(jm->jm_metadata);
  if(jm->jm_options)   prop_ref_dec(jm->jm_options);
  if(jm->jm_eventsink) prop_ref_dec(jm->jm_eventsink);

  if(jm->jm_pc != NULL)
    prop_courier_destroy(jm->jm_pc);
  free(jm->jm_url);
  free(jm);
}
예제 #5
0
파일: es_gumbo.c 프로젝트: Cy-4AH/showtime
static void
es_gumbo_find_by_class_r(GumboNode *node, char **classes, duk_context *ctx,
                         int *idxp, es_gumbo_output_t *ego)
{
  if(node->type != GUMBO_NODE_ELEMENT && node->type != GUMBO_NODE_TEMPLATE)
    return;

  const GumboElement *e = &node->v.element;
  GumboAttribute *a = gumbo_get_attribute(&e->attributes, "class");

  if(a != NULL) {
    char **list = strvec_split(a->value, ' ');
    for(int i = 0; classes[i] != NULL; i++) {
      int found = 0;
      for(int j = 0; list[j] != NULL; j++) {
        if(!strcmp(list[j], classes[i])) {
          found = 1;
          break;
        }
      }
      if(!found)
        goto notfound;
    }
    push_gumbo_node(ctx, node, ego);
    duk_put_prop_index(ctx, -2, (*idxp)++);

  notfound:
    strvec_free(list);
  }

  for(int i = 0; i < e->children.length; i++)
    es_gumbo_find_by_class_r(e->children.data[i], classes, ctx, idxp, ego);
}
예제 #6
0
static prop_t *
prop_from_path(const char *path)
{
  char **n = strvec_split(path, '/');
  prop_t *p = prop_get_by_name((const char **)n, 1, NULL);
  strvec_free(n);
  return p;
}
예제 #7
0
파일: es_gumbo.c 프로젝트: Cy-4AH/showtime
static int
es_gumbo_find_by_class(duk_context *ctx)
{
  es_gumbo_node_t *egn = es_get_native_obj(ctx, 0, &es_native_gumbo_node);
  const char *cls = duk_to_string(ctx, 1);
  int idx = 0;
  duk_push_array(ctx);
  char **classlist = strvec_split(cls, ' ');
  es_gumbo_find_by_class_r(egn->node, classlist, ctx, &idx, egn->output);
  strvec_free(classlist);
  return 1;
}
예제 #8
0
파일: argvenvp.c 프로젝트: neeraj9/sbox2
/* Map script interpreter:
 * Called with "rule" and "exec_policy" already in lua's stack,
 * leaves (possibly modified) "rule" and "exec_policy" to lua's stack.
*/
char *sb_execve_map_script_interpreter(
    const char *interpreter,
    const char *interp_arg,
    const char *mapped_script_filename,
    const char *orig_script_filename,
    char ***argv,
    char ***envp)
{
    struct lua_instance *luaif;
    char *mapped_interpreter;
    int new_argc, new_envc;
    int res;

    luaif = get_lua();
    if (!luaif) return(0);

    if (!argv || !envp) {
        SB_LOG(SB_LOGLEVEL_ERROR,
               "ERROR: sb_execve_map_script_interpreter: "
               "(argv || envp) == NULL");
        release_lua(luaif);
        return NULL;
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: gettop=%d"
           " interpreter=%s interp_arg=%s "
           "mapped_script_filename=%s orig_script_filename=%s",
           lua_gettop(luaif->lua), interpreter, interp_arg,
           mapped_script_filename, orig_script_filename);

    lua_getfield(luaif->lua, LUA_GLOBALSINDEX,
                 "sb_execve_map_script_interpreter");

    /* stack now contains "rule", "exec_policy" and
     * "sb_execve_map_script_interpreter".
     * move "sb_execve_map_script_interpreter" to the bottom : */
    lua_insert(luaif->lua, -3);

    lua_pushstring(luaif->lua, interpreter);
    if (interp_arg) lua_pushstring(luaif->lua, interp_arg);
    else lua_pushnil(luaif->lua);
    lua_pushstring(luaif->lua, mapped_script_filename);
    lua_pushstring(luaif->lua, orig_script_filename);
    strvec_to_lua_table(luaif, *argv);
    strvec_to_lua_table(luaif, *envp);

    /* args: rule, exec_policy, interpreter, interp_arg,
     *	 mapped_script_filename, orig_script_filename,
     *	 argv, envp
     * returns: rule, policy, result, mapped_interpreter, #argv, argv,
     *	#envp, envp
     * "result" is one of:
     *  0: argv / envp were modified; mapped_interpreter was set
     *  1: argv / envp were not modified; mapped_interpreter was set
     * -1: deny exec.
    */
    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter M1", luaif->lua);
    }
    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: call lua, gettop=%d",
           lua_gettop(luaif->lua));
    lua_call(luaif->lua, 8, 8);
    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: return from lua, gettop=%d",
           lua_gettop(luaif->lua));
    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter M2", luaif->lua);
    }

    mapped_interpreter = (char *)lua_tostring(luaif->lua, -5);
    if (mapped_interpreter) mapped_interpreter = strdup(mapped_interpreter);

    res = lua_tointeger(luaif->lua, -6);
    switch (res) {

    case 0:
        /* exec arguments were modified, replace contents of
         * argv and envp vectors */
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: Updated argv&envp");

        strvec_free(*argv);
        new_argc = lua_tointeger(luaif->lua, -4);
        lua_string_table_to_strvec(luaif, -3, argv, new_argc);

        new_envc = lua_tointeger(luaif->lua, -2);
        strvec_free(*envp);
        lua_string_table_to_strvec(luaif, -1, envp, new_envc);

        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;

    case 1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: argv&envp were not modified");
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;

    case 2:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: use sbox_map_path_for_exec");
        /* remove all return values from the stack. */
        lua_pop(luaif->lua, 8);
        if (mapped_interpreter) free(mapped_interpreter);
        mapped_interpreter = NULL;
        {
            mapping_results_t	mapping_result;

            clear_mapping_results_struct(&mapping_result);
            sbox_map_path_for_exec("script_interp",
                                   interpreter, &mapping_result);
            if (mapping_result.mres_result_buf) {
                mapped_interpreter =
                    strdup(mapping_result.mres_result_buf);
            }
            free_mapping_results(&mapping_result);
        }
        SB_LOG(SB_LOGLEVEL_DEBUG, "sb_execve_map_script_interpreter: "
               "interpreter=%s mapped_interpreter=%s",
               interpreter, mapped_interpreter);
        break;

    case -1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: exec denied");
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        if (mapped_interpreter) free(mapped_interpreter);
        mapped_interpreter = NULL;
        break;

    default:
        SB_LOG(SB_LOGLEVEL_ERROR,
               "sb_execve_map_script_interpreter: Unsupported result %d", res);
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;
    }


    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter E2", luaif->lua);
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: at exit, gettop=%d",
           lua_gettop(luaif->lua));
    release_lua(luaif);
    return mapped_interpreter;
}
예제 #9
0
파일: argvenvp.c 프로젝트: neeraj9/sbox2
/* Exec Postprocessing:
 * Called with "rule" and "exec_policy" already in lua's stack.
*/
int sb_execve_postprocess(char *exec_type,
                          char **mapped_file,
                          char **filename,
                          const char *binary_name,
                          char ***argv,
                          char ***envp)
{
    struct lua_instance *luaif;
    int res, new_argc;
    int replace_environment = 0;

    luaif = get_lua();
    if (!luaif) return(0);

    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_postprocess entry", luaif->lua);
    }

    if (!argv || !envp) {
        SB_LOG(SB_LOGLEVEL_ERROR,
               "ERROR: sb_argvenvp: (argv || envp) == NULL");
        release_lua(luaif);
        return -1;
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_postprocess: gettop=%d", lua_gettop(luaif->lua));

    lua_getfield(luaif->lua, LUA_GLOBALSINDEX, "sb_execve_postprocess");

    /* stack now contains "rule", "exec_policy" and "sb_execve_postprocess".	 * move "sb_execve_postprocess" to the bottom : */
    lua_insert(luaif->lua, -3);

    lua_pushstring(luaif->lua, exec_type);
    lua_pushstring(luaif->lua, *mapped_file);
    lua_pushstring(luaif->lua, *filename);
    lua_pushstring(luaif->lua, binary_name);
    strvec_to_lua_table(luaif, *argv);
    strvec_to_lua_table(luaif, *envp);

    /* args: rule, exec_policy, exec_type, mapped_file, filename,
     *	 binaryname, argv, envp
     * returns: res, mapped_file, filename, argc, argv, envc, envp */
    lua_call(luaif->lua, 8, 7);

    res = lua_tointeger(luaif->lua, -7);
    switch (res) {

    case 0:
        /* exec arguments were modified, replace contents of
         * argv vector */
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: Updated argv&envp");
        free(*mapped_file);
        *mapped_file = strdup(lua_tostring(luaif->lua, -6));

        free(*filename);
        *filename = strdup(lua_tostring(luaif->lua, -5));

        strvec_free(*argv);
        new_argc = lua_tointeger(luaif->lua, -4);
        lua_string_table_to_strvec(luaif, -3, argv, new_argc);

        replace_environment = 1;
        break;

    case 1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: argv was not modified");
        /* always update environment when we are going to exec */
        replace_environment = 1;
        break;

    case -1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: exec denied");
        break;

    default:
        SB_LOG(SB_LOGLEVEL_ERROR,
               "sb_execve_postprocess: Unsupported result %d", res);
        break;
    }

    if (replace_environment) {
        int new_envc;
        new_envc = lua_tointeger(luaif->lua, -2);
        strvec_free(*envp);
        lua_string_table_to_strvec(luaif, -1, envp, new_envc);
    }

    /* remove sb_execve_postprocess return values from the stack.  */
    lua_pop(luaif->lua, 7);

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_postprocess: at exit, gettop=%d", lua_gettop(luaif->lua));
    release_lua(luaif);
    return res;
}
예제 #10
0
static JSBool 
js_createMultiOpt(JSContext *cx, JSObject *obj, uintN argc, 
		  jsval *argv, jsval *rval)
{
  js_setting_group_t *jsg = JS_GetPrivate(cx, obj);
  const char *id;
  const char *title;
  JSObject *func;
  JSObject *optlist;
  JSBool persistent = JS_FALSE;

  if(!JS_ConvertArguments(cx, argc, argv, "ssoo/b",
			  &id, &title, &optlist, &func, &persistent))
    return JS_FALSE;

  js_setting_t *jss = jss_create(cx, obj, id, rval, func, jsg, persistent);
  if(jss == NULL)
    return JS_FALSE;

  char **options = NULL;
  JSIdArray *opts, *opt;
  int i;

  char *defvalue = NULL;

  if((opts = JS_Enumerate(cx, optlist)) != NULL) {

    for(i = 0; i < opts->length; i++) {
      jsval name, value, id, title, def;
      if(!JS_IdToValue(cx, opts->vector[i], &name) ||
         !JSVAL_IS_INT(name) ||
         !JS_GetElement(cx, optlist, JSVAL_TO_INT(name), &value) ||
         !JSVAL_IS_OBJECT(value) ||
         (opt = JS_Enumerate(cx, JSVAL_TO_OBJECT(value))) == NULL)
        continue;

      if(opt->length >= 2 &&
         JS_GetElement(cx, JSVAL_TO_OBJECT(value), 0, &id) &&
         JS_GetElement(cx, JSVAL_TO_OBJECT(value), 1, &title)) {

        if(opt->length < 3 ||
           !JS_GetElement(cx, JSVAL_TO_OBJECT(value), 2, &def))
          def = JSVAL_FALSE;

        const char *k = JS_GetStringBytes(JS_ValueToString(cx, id));

        if(def == JSVAL_TRUE)
          mystrset(&defvalue, k);

        strvec_addp(&options, k);
        strvec_addp(&options, JS_GetStringBytes(JS_ValueToString(cx, title)));
      }
      JS_DestroyIdArray(cx, opt);
    }
    JS_DestroyIdArray(cx, opts);
  }

  rstr_t *r = NULL;
  if(persistent && jsg->jsg_kv_url)
    r = kv_url_opt_get_rstr(jsg->jsg_kv_url, KVSTORE_DOMAIN_PLUGIN, id);


  jss->jss_s =
    setting_create(SETTING_MULTIOPT, jsg->jsg_root,
                   SETTINGS_INITIAL_UPDATE | jsg->jsg_settings_flags,
                   SETTING_TITLE_CSTR(title),
                   SETTING_COURIER(js_global_pc),
                   SETTING_CALLBACK(js_store_update_string, jss),
                   SETTING_VALUE(r ? rstr_get(r) : defvalue),
                   SETTING_OPTION_LIST(options),
                   SETTING_HTSMSG_CUSTOM_SAVER(id, jsg->jsg_store,
                                               js_setting_group_save, jsg),
                   NULL);

  strvec_free(options);
  rstr_release(r);
  jss->jss_cx = NULL;
  return JS_TRUE;
}
예제 #11
0
파일: argvenvp.c 프로젝트: OlegGirko/ldbox
/* Exec Postprocessing:
*/
int lb_execve_postprocess(const char *exec_type,
	const char *exec_policy_name,
	char **mapped_file,
	char **filename,
	const char *binary_name,
	char ***argv,
	char ***envp)
{
	struct lbcontext *lbctx;
	int res, new_argc;
	int replace_environment = 0;
	PROCESSCLOCK(clk1)

	START_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, "lb_execve_postprocess");
	lbctx = get_lbcontext_lua();
	if (!lbctx) return(0);

	if(LB_LOG_IS_ACTIVE(LB_LOGLEVEL_NOISE3)) {
		dump_lua_stack("lb_execve_postprocess entry", lbctx->lua);
	}

	if (!argv || !envp) {
		LB_LOG(LB_LOGLEVEL_ERROR,
			"ERROR: lb_argvenvp: (argv || envp) == NULL");
		release_lbcontext(lbctx);
		return -1;
	}

	LB_LOG(LB_LOGLEVEL_NOISE,
		"lb_execve_postprocess: gettop=%d", lua_gettop(lbctx->lua));

	lua_getfield(lbctx->lua, LUA_GLOBALSINDEX, "lb_execve_postprocess");

	lua_pushstring(lbctx->lua, exec_policy_name);
	lua_pushstring(lbctx->lua, exec_type);
	lua_pushstring(lbctx->lua, *mapped_file);
	lua_pushstring(lbctx->lua, *filename);
	lua_pushstring(lbctx->lua, binary_name);
	strvec_to_lua_table(lbctx, *argv);
	strvec_to_lua_table(lbctx, *envp);

	/* args: exec_policy_name, exec_type, mapped_file, filename,
	 *	 binaryname, argv, envp
	 * returns: res, mapped_file, filename, argc, argv, envc, envp */
	lua_call(lbctx->lua, 7, 7);
	
	res = lua_tointeger(lbctx->lua, -7);
	switch (res) {

	case 0:
		/* exec arguments were modified, replace contents of
		 * argv vector */
		LB_LOG(LB_LOGLEVEL_DEBUG,
			"lb_execve_postprocess: Updated argv&envp");
		free(*mapped_file);
		*mapped_file = strdup(lua_tostring(lbctx->lua, -6));

		free(*filename);
		*filename = strdup(lua_tostring(lbctx->lua, -5));

		strvec_free(*argv);
		new_argc = lua_tointeger(lbctx->lua, -4);
		lua_string_table_to_strvec(lbctx->lua, -3, argv, new_argc);

		replace_environment = 1;
		break;

	case 1:
		LB_LOG(LB_LOGLEVEL_DEBUG,
			"lb_execve_postprocess: argv was not modified");
		/* always update environment when we are going to exec */
		replace_environment = 1;
		break;

	case -1:
		LB_LOG(LB_LOGLEVEL_DEBUG,
			"lb_execve_postprocess: exec denied");
		break;

	default:
		LB_LOG(LB_LOGLEVEL_ERROR,
			"lb_execve_postprocess: Unsupported result %d", res);
		break;
	}

	if (replace_environment) {
		int new_envc;
		new_envc = lua_tointeger(lbctx->lua, -2);
		strvec_free(*envp);
		lua_string_table_to_strvec(lbctx->lua, -1, envp, new_envc);
	}

	/* remove lb_execve_postprocess return values from the stack.  */
	lua_pop(lbctx->lua, 7);

	STOP_AND_REPORT_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, mapped_file);

	LB_LOG(LB_LOGLEVEL_NOISE,
		"lb_execve_postprocess: at exit, gettop=%d", lua_gettop(lbctx->lua));
	release_lbcontext(lbctx);
	return res;
}