void _ostree_kernel_args_append (OstreeKernelArgs *kargs, const char *arg) { gboolean existed = TRUE; GPtrArray *values; char *duped = g_strdup (arg); const char *val = split_keyeq (duped); values = g_hash_table_lookup (kargs->table, duped); if (!values) { values = g_ptr_array_new_with_free_func (g_free); existed = FALSE; } g_ptr_array_add (values, g_strdup (val)); if (!existed) { g_hash_table_replace (kargs->table, duped, values); g_ptr_array_add (kargs->order, duped); } else { g_free (duped); } }
/* * Note: this is a new function added to the API * * _ostree_kernel_args_delete: * @kargs: a OstreeKernelArgs instance * @arg: key or key/value pair for deletion * @error: an GError instance * * There are few scenarios being handled for deletion: * * 1: for input arg with a single key(i.e without = for split), * the key/value pair will be deleted if there is only * one value that is associated with the key * * 2: for input arg wth key/value pair, the specific key * value pair will be deleted from the pointer array * if those exist. * * 3: If the found key has only one value * associated with it, the key entry in the table will also * be removed, and the key will be removed from order table * * Returns: False if an error is set, * **/ gboolean _ostree_kernel_args_delete (OstreeKernelArgs *kargs, const char *arg, GError **error) { OstreeKernelArgQueryFlag query_flag = 0; int value_index; if (!_ostree_kernel_arg_query_status (kargs, arg, &query_flag, FALSE, &value_index, error)) return FALSE; /* We then know the arg can be found and is valid currently */ g_autofree char *arg_owned = g_strdup (arg); split_keyeq (arg_owned); GPtrArray *values = g_hash_table_lookup (kargs->table, arg_owned); /* This tells us to delete that key directly */ if (query_flag == OSTREE_KERNEL_ARG_KEY_ONE_VALUE) return _ostree_kernel_args_delete_key_entry (kargs, arg_owned, error); else if (query_flag == OSTREE_KERNEL_ARG_FOUND_KEY_MULTI_VALUE) { g_ptr_array_remove_index (values, value_index); return TRUE; } else g_assert_not_reached(); }
/* * Note: this function is newly added to the API * * _ostree_kernel_arg_new_replace: * @kargs: OstreeKernelArgs instance * @arg: a string argument * @error: error instance * * This function implements the basic logic behind key/value pair * replacement. Do note that the arg need to be properly formatted * * When replacing key with exact one value, the arg can be in * the form: * key, key=new_val, or key=old_val=new_val * The first one swaps the old_val with the key to an empty value * The second and third replace the old_val into the new_val * * When replacing key with multiple values, the arg can only be * in the form of: * key=old_val=new_val. Unless there is a special case where * there is an empty value associated with the key, then * key=new_val will work because old_val is empty. The empty * val will be swapped with the new_val in that case * * Returns: False if an error is set **/ gboolean _ostree_kernel_args_new_replace (OstreeKernelArgs *kargs, const char *arg, GError **error) { OstreeKernelArgQueryFlag query_flag = 0; int value_index; if (!_ostree_kernel_arg_query_status (kargs, arg, &query_flag, TRUE, &value_index, error)) return FALSE; g_autofree char *arg_owned = g_strdup (arg); g_autofree char *old_val = g_strdup (split_keyeq (arg_owned)); const char *possible_new_val = (query_flag == OSTREE_KERNEL_ARG_REPLACE_NO_SECOND_SPLIT) ? old_val : split_keyeq (old_val); /* Similar to the delete operations, we verified in the function * earlier that the arguments are valid, thus no check * performed here */ GPtrArray *values = g_hash_table_lookup (kargs->table, arg_owned); /* We find the old one, we free the old memory, * then put new one back in */ char *old_element = (char *)g_ptr_array_index (values, value_index); g_free (g_steal_pointer (&old_element)); /* Then we assign the index to the new value */ g_ptr_array_index (values, value_index) = g_strdup (possible_new_val); return TRUE; }
void _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, char *arg) { gboolean existed; GPtrArray *values = g_ptr_array_new_with_free_func (g_free); const char *value = split_keyeq (arg); existed = g_hash_table_remove (kargs->table, arg); if (!existed) g_ptr_array_add (kargs->order, arg); g_ptr_array_add (values, g_strdup (value)); g_hash_table_replace (kargs->table, arg, values); }
void _ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, char *arg) { gboolean existed; GPtrArray *values = g_ptr_array_new_with_free_func (g_free); const char *value = split_keyeq (arg); gpointer old_key; g_ptr_array_add (values, g_strdup (value)); existed = g_hash_table_lookup_extended (kargs->table, arg, &old_key, NULL); if (existed) { g_hash_table_replace (kargs->table, old_key, values); g_free (arg); } else { g_ptr_array_add (kargs->order, arg); g_hash_table_replace (kargs->table, arg, values); } }
/* * Note: this function is newly added to the API * * _ostree_query_arg_status: * @kargs: A OstreeKernelArg instance * @arg: a string to 'query status' (find its validity) * @out_query_flag: a OstreeKernelArgQueryFlag, used to tell the caller result of finding * @is_replaced: tell if the caller is from replace or delete * @out_index: if successfully found, return the arg's index * @error: an error instance * * This function provides check for the argument string * to see if it is valid for deletion/replacement. More * detailed explanation can be found in delete/replace section. * * Returns: False if an error is set */ static gboolean _ostree_kernel_arg_query_status (OstreeKernelArgs *kargs, const char *arg, OstreeKernelArgQueryFlag *out_query_flag, gboolean is_replaced, int *out_index, GError **error) { g_autofree char *arg_owned = g_strdup (arg); g_autofree char *val = g_strdup (split_keyeq (arg_owned)); /* For replaced, it is a special case, we allow * key=value=new_value, thus, this split is to * discard the new value if there is one */ const char *replaced_val = split_keyeq (val); const gboolean key_only = !*val; GPtrArray *values = g_hash_table_lookup (kargs->table, arg_owned); if (!values) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to find kernel argument '%s'", arg_owned); return FALSE; } const gboolean single_value = values->len == 1; /* See if the value is inside the value list */ if (!_ostree_ptr_array_find (values, val, out_index)) { /* Both replace and delete support empty value handlation * thus adding a condition here to handle it separately */ if (key_only && single_value) { *out_query_flag = OSTREE_KERNEL_ARG_KEY_ONE_VALUE; return TRUE; } /* This is a special case for replacement where * there is only one single key, and the second val * will now represent the new value (no second split * will happen this case) */ else if (is_replaced && single_value && !*replaced_val) { *out_query_flag = OSTREE_KERNEL_ARG_REPLACE_NO_SECOND_SPLIT; return TRUE; } /* Handle both no value case, and the case when inputting key=value for a replacement */ else if ((key_only || (is_replaced && !*replaced_val)) && !single_value) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unable to %s argument '%s' with multiple values", is_replaced ? "replace" : "delete", arg_owned); return FALSE; } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "There is no %s value for key %s", val, arg_owned); return FALSE; } } /* We set the flag based on values len, used by replace or delete for better case handling */ if (single_value) *out_query_flag = OSTREE_KERNEL_ARG_KEY_ONE_VALUE; else *out_query_flag = OSTREE_KERNEL_ARG_FOUND_KEY_MULTI_VALUE; return TRUE; }