PolicyKit: Branch 'master'
David Zeuthen
david at kemper.freedesktop.org
Wed Nov 21 14:08:55 PST 2007
src/kit/kit-spawn.c | 1
src/kit/kit-string.c | 462 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/kit/kit-string.h | 22 ++
3 files changed, 484 insertions(+), 1 deletion(-)
New commits:
commit cec99e3c4e22c62bef02806ec7682f720b834a57
Author: David Zeuthen <davidz at redhat.com>
Date: Wed Nov 21 17:08:22 2007 -0500
add support for percent encoding/decoding and colon separated kv-lists
diff --git a/src/kit/kit-spawn.c b/src/kit/kit-spawn.c
index 6fb803a..2f90f97 100644
--- a/src/kit/kit-spawn.c
+++ b/src/kit/kit-spawn.c
@@ -149,6 +149,7 @@ out:
/**
* kit_spawn_sync:
* @working_directory: Working directory for child or #NULL to inherit parents
+ * @flags: A combination of flags from #KitSpawnFlags
* @argv: #NULL terminated argument vector
* @envp: #NULL terminated environment or #NULL to inherit parents;
* @stdin: String to write to stdin of child or #NULL
diff --git a/src/kit/kit-string.c b/src/kit/kit-string.c
index a3d4037..ef1ccd4 100644
--- a/src/kit/kit-string.c
+++ b/src/kit/kit-string.c
@@ -31,6 +31,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+
#include <kit/kit.h>
#include "kit-test.h"
@@ -367,17 +369,476 @@ oom:
return NULL;
}
+static kit_bool_t
+_is_reserved (char c)
+{
+ unsigned int n;
+ char reserved[] = " !*'();:@&=+$,/?%#[]";
+
+ for (n = 0; n < sizeof (reserved); n++) {
+ if (reserved[n] == c)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char
+_to_hex (unsigned int nibble)
+{
+ if (nibble < 10)
+ return nibble + '0';
+ else
+ return nibble - 10 + 'A';
+}
+
+/**
+ * kit_string_percent_encode:
+ * @buf: return location for output
+ * @buf_size: size of buffer
+ * @s: string to encode
+ *
+ * Percent encodes a string; each occurence of an ASCII characters in
+ * the set <literal>" !*'();:@&=+$,/?%#[]"</literal> will be replaced
+ * by a three character sequence started by the percent sign "%" and
+ * then the hexidecimal representation of the ASCII character in
+ * question.
+ *
+ * Returns: This function do not write more than @buf_size bytes
+ * (including the trailing zero). If the output was truncated due to
+ * this limit then the return value is the number of characters (not
+ * including the trailing zero) which would have been written to the
+ * final string if enough space had been available. Thus, a return
+ * value of size or more means that the output was truncated.
+ */
+size_t
+kit_string_percent_encode (char *buf, size_t buf_size, const char *s)
+{
+ size_t len;
+ unsigned int n;
+ unsigned int m;
+
+ kit_return_val_if_fail (buf != NULL, 0);
+ kit_return_val_if_fail (s != NULL, 0);
+
+ len = strlen (s);
+
+ for (n = 0, m = 0; n < len; n++) {
+ int c = s[n];
+
+ if (_is_reserved (c)) {
+ if (m < buf_size)
+ buf[m] = '%';
+ m++;
+ if (m < buf_size)
+ buf[m] = _to_hex (c >> 4);
+ m++;
+ if (m < buf_size)
+ buf[m] = _to_hex (c & 0x0f);
+ m++;
+ } else {
+ if (m < buf_size)
+ buf[m] = c;
+ m++;
+ }
+ }
+ if (m < buf_size)
+ buf[m] = '\0';
+
+ return m;
+}
+
+/**
+ * kit_string_percent_decode:
+ * @s: string to modify in place
+ *
+ * Percent-decodes a string in place. See kit_string_percent_encode()
+ * for details on the encoding format.
+ *
+ * Returns: %FALSE if string is not properly encoded (and errno will be set to EINVAL)
+ */
+kit_bool_t
+kit_string_percent_decode (char *s)
+{
+ kit_bool_t ret;
+ unsigned int n;
+ unsigned int m;
+ size_t len;
+
+ kit_return_val_if_fail (s != NULL, FALSE);
+
+ ret = FALSE;
+
+ len = strlen (s);
+
+ for (n = 0, m = 0; n < len; n++) {
+ int c = s[n];
+
+ if (c != '%') {
+ if (_is_reserved (c)) {
+ errno = EINVAL;
+ goto out;
+ }
+ s[m++] = s[n];
+ } else {
+ int nibble1;
+ int nibble2;
+
+ if (n + 2 >= len) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ nibble1 = s[n + 1];
+ nibble2 = s[n + 2];
+ n += 2;
+
+ if (nibble1 >= '0' && nibble1 <= '9') {
+ nibble1 -= '0';
+ } else if (nibble1 >= 'A' && nibble1 <= 'F') {
+ nibble1 -= 'A' - 10;
+ } else {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (nibble2 >= '0' && nibble2 <= '9') {
+ nibble2 -= '0';
+ } else if (nibble2 >= 'A' && nibble2 <= 'F') {
+ nibble2 -= 'A' - 10;
+ } else {
+ errno = EINVAL;
+ goto out;
+ }
+
+ s[m++] = (nibble1 << 4) | nibble2;
+ }
+ }
+ s[m] = '\0';
+
+ ret = TRUE;
+out:
+ return ret;
+}
+
+
+/**
+ * kit_string_entry_parse:
+ * @entry: line to parse
+ * @func: callback function
+ * @user_data: user data to pass to @func
+ *
+ * Parse a line of the form
+ * <literal>key1=val1:key2=val2:key3=val3</literal>.
+ *
+ * The given @entry is said not to be wellformed if a) it doesn't
+ * follow this structure (for example
+ * <literal>key1=val1:key2:key3=val3</literal> is not well-formed
+ * because it's missing the '=' character) or the extracted key and
+ * value strings are not properly percent encoded.
+ *
+ * Both the key and value values are run through the
+ * kit_string_percent_decode() function prior to being passed to
+ * @func. Normally this function is used to decode strings produced
+ * with kit_string_entry_create().
+ *
+ * Returns: %TRUE if the line is wellformed and the callback didn't
+ * short-circuit the iteration. Returns %FALSE on OOM (and errno will
+ * be set to ENOMEM) or if @entry is not wellformed (and errno will
+ * be set to EINVAL).
+ */
+kit_bool_t
+kit_string_entry_parse (const char *entry, KitStringEntryParseFunc func, void *user_data)
+{
+ unsigned int n;
+ kit_bool_t ret;
+ char **tokens;
+ size_t num_tokens;
+
+ kit_return_val_if_fail (entry != NULL, FALSE);
+ kit_return_val_if_fail (func != NULL, FALSE);
+
+ ret = FALSE;
+ tokens = NULL;
+
+ tokens = kit_strsplit (entry, ':', &num_tokens);
+ if (tokens == NULL) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ for (n = 0; n < num_tokens; n++) {
+ char *token;
+ char *p;
+
+ token = tokens[n];
+
+ p = strchr (token, '=');
+ if (p == NULL) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ token [p - token] = '\0';
+
+ p++;
+
+ if (!kit_string_percent_decode (token))
+ goto out;
+
+ if (!kit_string_percent_decode (p))
+ goto out;
+
+ if (!func (token, p, user_data)) {
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+
+out:
+ if (tokens != NULL)
+ kit_strfreev (tokens);
+ return ret;
+}
+
+/**
+ * kit_string_entry_createv:
+ * @buf: return location for output
+ * @buf_size: size of buffer
+ * @kv_pairs: %NULL terminated array of key/value pairs.
+ *
+ * Takes an array of key/value pairs and generates a string
+ * <literal>"k1=v1:k2=v2:...:k_n=v_n"</literal> where
+ * <literal>k_i</literal> and <literal>v_i</literal> are percent
+ * encoded representations of the given key/value pairs.
+ *
+ * The string can later be parsed with kit_string_entry_parse() to get
+ * the exact same list of key/value pairs back.
+ *
+ * Returns: This function do not write more than @buf_size bytes
+ * (including the trailing zero). If the output was truncated due to
+ * this limit then the return value is the number of characters (not
+ * including the trailing zero) which would have been written to the
+ * final string if enough space had been available. Thus, a return
+ * value of size or more means that the output was truncated.
+ *
+ * If an uneven number of strings are given, this function will return
+ * zero and errno will be set to EINVAL.
+ */
+size_t
+kit_string_entry_createv (char *buf, size_t buf_size, const char *kv_pairs[])
+{
+ int n;
+ unsigned int m;
+
+ for (n = 0, m = 0; kv_pairs[n] != NULL; n+= 2) {
+ const char *key;
+ const char *value;
+
+ if (kv_pairs[n + 1] == NULL) {
+ m = 0;
+ errno = EINVAL;
+ goto out;
+ }
+
+ key = kv_pairs[n];
+ value = kv_pairs[n + 1];
+
+ if (n > 0) {
+ if (m < buf_size)
+ buf[m] = ':';
+ m++;
+ }
+
+ m += kit_string_percent_encode (buf + m, buf_size - m > 0 ? buf_size - m : 0, key);
+
+ if (m < buf_size)
+ buf[m] = '=';
+ m++;
+
+ m += kit_string_percent_encode (buf + m, buf_size - m > 0 ? buf_size - m : 0, value);
+ }
+
+out:
+ if (m < buf_size)
+ buf[m] = '\0';
+
+ return m;
+}
+
+/**
+ * kit_string_entry_create:
+ * @buf: return location for output
+ * @buf_size: size of buffer
+ * @...: %NULL terminated array of key/value pairs.
+ *
+ * See kit_string_entry_create().
+ *
+ * Returns: See kit_string_entry_create(). Up to 64 pairs can be
+ * passed; if there are more pairs, this function will return zero and
+ * errno will be set to EOVERFLOW.
+ */
+size_t
+kit_string_entry_create (char *buf, size_t buf_size, ...)
+{
+ int n;
+ va_list args;
+ const char *val;
+ const char *kv_pairs[64 * 2 + 1];
+ size_t ret;
+
+ /* TODO: get rid of the 64 limit... */
+
+ ret = 0;
+
+ n = 0;
+ va_start (args, buf_size);
+ while ((val = va_arg (args, const char *)) != NULL) {
+ if (n == 64 * 2) {
+ errno = EOVERFLOW;
+ goto out;
+ }
+ kv_pairs[n++] = val;
+ }
+ va_end (args);
+ kv_pairs[n] = NULL;
+
+ ret = kit_string_entry_createv (buf, buf_size, kv_pairs);
+out:
+ return ret;
+}
#ifdef KIT_BUILD_TESTS
static kit_bool_t
+_ep1 (const char *key, const char *value, void *user_data)
+{
+ int *n = (int *) user_data;
+
+ if (strcmp (key, "a") == 0 && strcmp (value, "aval") == 0)
+ *n += 1;
+ if (strcmp (key, "a") == 0 && strcmp (value, "aval2") == 0)
+ *n += 1;
+ if (strcmp (key, "b") == 0 && strcmp (value, "bval") == 0)
+ *n += 1;
+ if (strcmp (key, "c") == 0 && strcmp (value, "cval") == 0)
+ *n += 1;
+ if (strcmp (key, "some_other_key") == 0 && strcmp (value, "some_value") == 0)
+ *n += 1;
+ if (strcmp (key, "escaped;here:right=") == 0 && strcmp (value, "yes! it's ==:crazy!") == 0)
+ *n += 1;
+
+ return TRUE;
+}
+
+static kit_bool_t
+_ep2 (const char *key, const char *value, void *user_data)
+{
+ int *n = (int *) user_data;
+
+ if (strcmp (key, "b") == 0)
+ return FALSE;
+
+ *n += 1;
+
+ return TRUE;
+}
+
+static kit_bool_t
_run_test (void)
{
+ int num;
char str[] = "Hello world";
char *p;
char *p2;
char **tokens;
size_t num_tokens;
+ unsigned int n;
+ char *bad_strings[] = {"bad:",
+ "bad=",
+ "bad%",
+ "bad%1",
+ "bad%xy",
+ "bad%1x",
+ "bad%Ax",
+ "bad%2a"};
+ char buf[256];
+
+ kit_assert (kit_string_percent_encode (buf, sizeof (buf), "Hello World; Nice day!") < sizeof (buf));
+ kit_assert (strcmp (buf, "Hello%20World%3B%20Nice%20day%21") == 0);
+ kit_assert (kit_string_percent_decode (buf));
+ kit_assert (strcmp (buf, "Hello World; Nice day!") == 0);
+
+ for (n = 0; n < sizeof (bad_strings) / sizeof (char *); n++) {
+ if ((p = kit_strdup (bad_strings[n])) != NULL) {
+ kit_assert (!kit_string_percent_decode (p) && errno == EINVAL);
+ kit_free (p);
+ }
+ }
+
+ kit_assert (kit_string_entry_create (buf, sizeof (buf),
+ "key1", "val1",
+ "key2", "val2",
+ "key3", "val3",
+ NULL) < sizeof (buf) &&
+ strcmp (buf, "key1=val1:key2=val2:key3=val3") == 0);
+
+ kit_assert (kit_string_entry_create (buf, sizeof (buf),
+ "key1;", "val1=val1x",
+ "key2%", "val2!",
+ NULL) < sizeof (buf) &&
+ strcmp (buf, "key1%3B=val1%3Dval1x:key2%25=val2%21") == 0);
+
+ kit_assert (kit_string_entry_create (buf, sizeof (buf),
+ "key1", "val1",
+ "key2", NULL) == 0 && errno == EINVAL);
+
+ kit_assert (kit_string_entry_create (buf, 3,
+ "key1", "val1",
+ "key2", "val2", NULL) > 3);
+
+ kit_assert (kit_string_entry_create (buf, sizeof (buf),
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a",
+ "b", "c", NULL) == 0 && errno == EOVERFLOW);
+
+ kit_assert (!kit_string_entry_parse ("key=val:invalidkeyval:key2=val2", _ep1, &num) &&
+ (errno == EINVAL || errno == ENOMEM));
+ kit_assert (!kit_string_entry_parse ("key;=val:key2=val2", _ep1, &num) &&
+ (errno == EINVAL || errno == ENOMEM));
+ kit_assert (!kit_string_entry_parse ("key=val:key2=val2;", _ep1, &num) &&
+ (errno == EINVAL || errno == ENOMEM));
+
+ kit_assert (kit_string_entry_create (buf, sizeof (buf),
+ "a", "aval",
+ "a", "aval2",
+ "b", "bval",
+ "c", "cval",
+ "some_other_key", "some_value",
+ "escaped;here:right=", "yes! it's ==:crazy!",
+ NULL) < sizeof (buf));
+ num = 0;
+ if (kit_string_entry_parse (buf, _ep1, &num)) {
+ kit_assert (num == 6);
+ } else {
+ kit_assert (errno == ENOMEM);
+ }
+
+ num = 0;
+ errno = 0;
+ kit_assert (!kit_string_entry_parse ("a=0:b=1:c=2", _ep2, &num));
+ if (num > 0)
+ kit_assert (errno == 0);
+ else
+ kit_assert (errno == ENOMEM);
+
if ((p = kit_strdup (str)) != NULL) {
kit_assert (strcmp (p, "Hello world") == 0);
@@ -445,7 +906,6 @@ _run_test (void)
kit_free (p);
}
-
return TRUE;
}
diff --git a/src/kit/kit-string.h b/src/kit/kit-string.h
index bebf5ef..c48c33e 100644
--- a/src/kit/kit-string.h
+++ b/src/kit/kit-string.h
@@ -48,6 +48,28 @@ char **kit_strsplit (const char *s, char delim, size_t *num_tokens);
void kit_strfreev (char **str_array);
size_t kit_strv_length (char **str_array);
+/**
+ * KitStringEntryParseFunc:
+ * @key: key of one of the entries
+ * @value: value of one of the entries
+ * @user_data: user data passed to kit_string_entry_parse()
+ *
+ * Type of callback function to use in kit_string_entry_parse()
+ *
+ * Returns: If %FALSE is returned the parsing will be aborted and
+ * kit_string_entry_parse() will return FALSE.
+ */
+typedef kit_bool_t (*KitStringEntryParseFunc) (const char *key, const char *value, void *user_data);
+
+kit_bool_t kit_string_entry_parse (const char *entry, KitStringEntryParseFunc func, void *user_data);
+
+kit_bool_t kit_string_percent_decode (char *s);
+size_t kit_string_percent_encode (char *buf, size_t buf_size, const char *s);
+
+size_t kit_string_entry_create (char *buf, size_t buf_size, ...);
+size_t kit_string_entry_createv (char *buf, size_t buf_size, const char *kv_pairs[]);
+
+
KIT_END_DECLS
#endif /* KIT_STRING_H */
More information about the hal-commit
mailing list