Thomas Haller 2017-05-19 09:46:22 +02:00
commit dfd72a623e
7 changed files with 446 additions and 137 deletions

View file

@ -21,6 +21,9 @@
each device in your application, use the object path. If you're looking
for a way to track a specific piece of hardware across reboot or hotplug,
use a MAC address or USB serial number.
Note that non-UTF-8 characters are backslash escaped. Use g_strcompress()
to obtain the true (non-UTF-8) string.
-->
<property name="Udi" type="s" access="read"/>
@ -28,6 +31,9 @@
Interface:
The name of the device's control (and often data) interface.
Note that non UTF-8 characters are backslash escaped, so the
resulting name may be longer then 15 characters. Use g_strcompress()
to revert the escaping.
-->
<property name="Interface" type="s" access="read"/>
@ -38,6 +44,9 @@
not refer to the actual data interface until the device has successfully
established a data connection, indicated by the device's State becoming
ACTIVATED.
Note that non UTF-8 characters are backslash escaped, so the
resulting name may be longer then 15 characters. Use g_strcompress()
to revert the escaping.
-->
<property name="IpInterface" type="s" access="read"/>
@ -45,6 +54,8 @@
Driver:
The driver handling the device.
Non-UTF-8 sequences are backslash escaped. Use g_strcompress()
to revert.
-->
<property name="Driver" type="s" access="read"/>
@ -52,6 +63,8 @@
DriverVersion:
The version of the driver handling the device.
Non-UTF-8 sequences are backslash escaped. Use g_strcompress()
to revert.
-->
<property name="DriverVersion" type="s" access="read"/>
@ -59,6 +72,8 @@
FirmwareVersion:
The firmware version for the device.
Non-UTF-8 sequences are backslash escaped. Use g_strcompress()
to revert.
-->
<property name="FirmwareVersion" type="s" access="read"/>

View file

@ -5323,6 +5323,100 @@ static void test_nm_utils_enum (void)
/*****************************************************************************/
static void
do_test_utils_str_utf8safe (const char *str, const char *expected, NMUtilsStrUtf8SafeFlags flags)
{
const char *str_safe, *s;
gs_free char *str2 = NULL;
gs_free char *str3 = NULL;
str_safe = nm_utils_str_utf8safe_escape (str, flags, &str2);
str3 = nm_utils_str_utf8safe_escape_cp (str, flags);
g_assert_cmpstr (str3, ==, str_safe);
g_assert ((!str && !str3) || (str != str3));
g_clear_pointer (&str3, g_free);
if (expected == NULL) {
g_assert (str_safe == str);
g_assert (!str2);
if (str) {
g_assert (!strchr (str, '\\'));
g_assert (g_utf8_validate (str, -1, NULL));
}
g_assert (str == nm_utils_str_utf8safe_unescape (str_safe, &str3));
g_assert (!str3);
str3 = nm_utils_str_utf8safe_unescape_cp (str_safe);
if (str) {
g_assert (str3 != str);
g_assert_cmpstr (str3, ==, str);
} else
g_assert (!str3);
g_clear_pointer (&str3, g_free);
return;
}
g_assert (str);
g_assert (str_safe != str);
g_assert (str_safe == str2);
g_assert ( strchr (str, '\\')
|| !g_utf8_validate (str, -1, NULL)
|| ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
&& NM_STRCHAR_ANY (str, ch, (guchar) ch >= 127))
|| ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)
&& NM_STRCHAR_ANY (str, ch, (guchar) ch < ' ')));
g_assert (g_utf8_validate (str_safe, -1, NULL));
str3 = g_strcompress (str_safe);
g_assert_cmpstr (str, ==, str3);
g_clear_pointer (&str3, g_free);
str3 = nm_utils_str_utf8safe_unescape_cp (str_safe);
g_assert (str3 != str);
g_assert_cmpstr (str3, ==, str);
g_clear_pointer (&str3, g_free);
s = nm_utils_str_utf8safe_unescape (str_safe, &str3);
g_assert (str3 != str);
g_assert (s == str3);
g_assert_cmpstr (str3, ==, str);
g_clear_pointer (&str3, g_free);
g_assert_cmpstr (str_safe, ==, expected);
}
static void
test_utils_str_utf8safe (void)
{
do_test_utils_str_utf8safe (NULL, NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\314", "\\314", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\314\315x\315\315x", "\\314\\315x\\315\\315x", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\314\315xx", "\\314\\315xx", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\314xx", "\\314xx", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\xa0", "\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\xe2\x91\xa0", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\xe2\xe2\x91\xa0", "\\342\xe2\x91\xa0", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("\xe2\xe2\x91\xa0\xa0", "\\342\xe2\x91\xa0\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("a", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("ab", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("ab\314", "ab\\314", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("ab\314adsf", "ab\\314adsf", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("abadsf", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("abäb", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("x\xa0", "x\\240", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("Ä\304ab\\äb", "Ä\\304ab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("Äab\\äb", "Äab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("ÄÄab\\äb", "ÄÄab\\\\äb", NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("㈞abä㈞b", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE);
do_test_utils_str_utf8safe ("abäb", "ab\\303\\244b", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII);
do_test_utils_str_utf8safe ("ab\ab", "ab\\007b", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL);
}
/*****************************************************************************/
static int
_test_nm_in_set_get (int *call_counter, gboolean allow_called, int value)
{
@ -5680,6 +5774,7 @@ int main (int argc, char **argv)
nmtst_init (&argc, &argv, TRUE);
/* The tests */
g_test_add_func ("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe);
g_test_add_func ("/core/general/test_nm_in_set", test_nm_in_set);
g_test_add_func ("/core/general/test_nm_in_strset", test_nm_in_strset);
g_test_add_func ("/core/general/test_setting_vpn_items", test_setting_vpn_items);

View file

@ -81,7 +81,7 @@ typedef struct {
GPtrArray *available_connections;
struct udev *udev;
char *product, *short_product;
char *product;
char *vendor, *short_vendor;
char *description, *bus_name;
@ -320,7 +320,6 @@ finalize (GObject *object)
g_free (priv->driver_version);
g_free (priv->firmware_version);
g_free (priv->product);
g_free (priv->short_product);
g_free (priv->vendor);
g_free (priv->short_vendor);
g_free (priv->description);
@ -1357,6 +1356,17 @@ _get_udev_property (NMDevice *device,
return db_value;
}
static char *
_get_udev_property_utf8safe (NMDevice *device,
const char *enc_prop, /* ID_XXX_ENC */
const char *db_prop) /* ID_XXX_FROM_DATABASE */
{
return nm_utils_str_utf8safe_escape_take (_get_udev_property (device,
enc_prop,
db_prop),
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL);
}
/**
* nm_device_get_product:
* @device: a #NMDevice
@ -1365,6 +1375,9 @@ _get_udev_property (NMDevice *device,
*
* Returns: the product name of the device. This is the internal string used by the
* device, and must not be modified.
*
* The string is backslash escaped (C escaping) for invalid characters. The escaping
* can be reverted with g_strcompress(), however the result may not be valid UTF-8.
**/
const char *
nm_device_get_product (NMDevice *device)
@ -1374,15 +1387,16 @@ nm_device_get_product (NMDevice *device)
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->product)
priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE");
if (!priv->product) {
priv->product = _get_udev_property_utf8safe (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE");
/* Sometimes ID_PRODUCT_FROM_DATABASE is used? */
if (!priv->product)
priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE");
/* Sometimes ID_PRODUCT_FROM_DATABASE is used? */
if (!priv->product)
priv->product = _get_udev_property_utf8safe (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE");
if (!priv->product)
priv->product = g_strdup ("");
if (!priv->product)
priv->product = g_strdup ("");
}
return priv->product;
}
@ -1395,6 +1409,9 @@ nm_device_get_product (NMDevice *device)
*
* Returns: the vendor name of the device. This is the internal string used by the
* device, and must not be modified.
*
* The string is backslash escaped (C escaping) for invalid characters. The escaping
* can be reverted with g_strcompress(), however the result may not be valid UTF-8.
**/
const char *
nm_device_get_vendor (NMDevice *device)
@ -1406,7 +1423,7 @@ nm_device_get_vendor (NMDevice *device)
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->vendor)
priv->vendor = _get_udev_property (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE");
priv->vendor = _get_udev_property_utf8safe (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE");
if (!priv->vendor)
priv->vendor = g_strdup ("");
@ -1414,128 +1431,146 @@ nm_device_get_vendor (NMDevice *device)
return priv->vendor;
}
static const char * const ignored_words[] = {
"Semiconductor",
"Components",
"Corporation",
"Communications",
"Company",
"Corp.",
"Corp",
"Co.",
"Inc.",
"Inc",
"Incorporated",
"Ltd.",
"Limited.",
"Intel?",
"chipset",
"adapter",
"[hex]",
"NDIS",
"Module",
NULL
};
static const char * const ignored_phrases[] = {
"Multiprotocol MAC/baseband processor",
"Wireless LAN Controller",
"Wireless LAN Adapter",
"Wireless Adapter",
"Network Connection",
"Wireless Cardbus Adapter",
"Wireless CardBus Adapter",
"54 Mbps Wireless PC Card",
"Wireless PC Card",
"Wireless PC",
"PC Card with XJACK(r) Antenna",
"Wireless cardbus",
"Wireless LAN PC Card",
"Technology Group Ltd.",
"Communication S.p.A.",
"Business Mobile Networks BV",
"Mobile Broadband Minicard Composite Device",
"Mobile Communications AB",
"(PC-Suite Mode)",
NULL
};
static char *
fixup_desc_string (const char *desc)
{
char *p, *temp;
char **words, **item;
GString *str;
static const char *const IGNORED_PHRASES[] = {
"Multiprotocol MAC/baseband processor",
"Wireless LAN Controller",
"Wireless LAN Adapter",
"Wireless Adapter",
"Network Connection",
"Wireless Cardbus Adapter",
"Wireless CardBus Adapter",
"54 Mbps Wireless PC Card",
"Wireless PC Card",
"Wireless PC",
"PC Card with XJACK(r) Antenna",
"Wireless cardbus",
"Wireless LAN PC Card",
"Technology Group Ltd.",
"Communication S.p.A.",
"Business Mobile Networks BV",
"Mobile Broadband Minicard Composite Device",
"Mobile Communications AB",
"(PC-Suite Mode)",
};
static const char *const IGNORED_WORDS[] = {
"Semiconductor",
"Components",
"Corporation",
"Communications",
"Company",
"Corp.",
"Corp",
"Co.",
"Inc.",
"Inc",
"Incorporated",
"Ltd.",
"Limited.",
"Intel?",
"chipset",
"adapter",
"[hex]",
"NDIS",
"Module",
};
char *desc_full;
char *p, *q;
int i;
if (!desc)
if (!desc || !desc[0])
return NULL;
p = temp = g_strdup (desc);
while (*p) {
if (*p == '_' || *p == ',')
/* restore original non-UTF-8-safe text. */
desc_full = nm_utils_str_utf8safe_unescape_cp (desc);
/* replace all invalid UTF-8 bytes with space. */
p = desc_full;
while (!g_utf8_validate (p, -1, (const char **) &q)) {
/* the byte is invalid UTF-8. Replace it with space and proceed. */
*q = ' ';
p = q + 1;
}
/* replace '_', ',', and ASCII controll characters with space. */
for (p = desc_full; p[0]; p++) {
if ( NM_IN_SET (*p, '_', ',')
|| *p < ' ')
*p = ' ';
p++;
}
/* Attempt to shorten ID by ignoring certain phrases */
for (i = 0; ignored_phrases[i]; i++) {
p = strstr (temp, ignored_phrases[i]);
for (i = 0; i < G_N_ELEMENTS (IGNORED_PHRASES); i++) {
p = strstr (desc_full, IGNORED_PHRASES[i]);
if (p) {
guint32 ignored_len = strlen (ignored_phrases[i]);
const char *eow = &p[strlen (IGNORED_PHRASES[i])];
memmove (p, p + ignored_len, strlen (p + ignored_len) + 1); /* +1 for the \0 */
memmove (p, eow, strlen (eow) + 1); /* +1 for the \0 */
}
}
/* Attempt to shorten ID by ignoring certain individual words */
words = g_strsplit (temp, " ", 0);
str = g_string_new_len (NULL, strlen (temp));
g_free (temp);
/* Attempt to shorten ID by ignoring certain individual words.
* - word-split the description at spaces
* - coalesce multiple spaces
* - skip over IGNORED_WORDS */
p = desc_full;
q = desc_full;
for (;;) {
char *eow;
gsize l;
for (item = words; *item; item++) {
gboolean ignore = FALSE;
/* skip leading spaces. */
while (p[0] == ' ')
p++;
if (**item == '\0')
continue;
if (!p[0])
break;
for (i = 0; ignored_words[i]; i++) {
if (!strcmp (*item, ignored_words[i])) {
ignore = TRUE;
break;
}
/* split leading word on first space */
eow = strchr (p, ' ');
if (eow)
*eow = '\0';
if (nm_utils_strv_find_first ((char **) IGNORED_WORDS,
G_N_ELEMENTS (IGNORED_WORDS),
p) < 0)
goto next;
l = strlen (p);
if (q != p) {
if (q != desc_full)
*q++ = ' ';
memmove (q, p, l);
}
q += l;
if (!ignore) {
if (str->len)
g_string_append_c (str, ' ');
g_string_append (str, *item);
}
next:
if (!eow)
break;
p = eow + 1;
}
g_strfreev (words);
temp = str->str;
g_string_free (str, FALSE);
*q++ = '\0';
return temp;
if (!desc_full[0]) {
g_free (desc_full);
return NULL;
}
nm_assert (g_utf8_validate (desc_full, -1, NULL));
return desc_full;
}
static void
get_description (NMDevice *device)
ensure_description (NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
const char *dev_product;
const char *dev_vendor;
char *pdown;
char *vdown;
GString *str;
GParamSpec *name_prop;
gs_free char *short_product = NULL;
dev_product = nm_device_get_product (device);
priv->short_product = fixup_desc_string (dev_product);
dev_vendor = nm_device_get_vendor (device);
priv->short_vendor = fixup_desc_string (dev_vendor);
priv->short_vendor = nm_str_realloc (fixup_desc_string (nm_device_get_vendor (device)));
/* Grab device's preferred name, if any */
name_prop = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (device)), "name");
@ -1546,28 +1581,24 @@ get_description (NMDevice *device)
g_clear_pointer (&priv->description, g_free);
}
if (!dev_product || !dev_vendor) {
priv->description = g_strdup (nm_device_get_iface (device));
if ( !priv->short_vendor
|| !(short_product = fixup_desc_string (nm_device_get_product (device)))) {
priv->description = g_strdup (nm_device_get_iface (device) ?: "");
return;
}
str = g_string_new_len (NULL, strlen (priv->short_vendor) + strlen (priv->short_product) + 1);
/* Another quick hack; if all of the fixed up vendor string
* is found in product, ignore the vendor.
*/
pdown = g_ascii_strdown (priv->short_product, -1);
vdown = g_ascii_strdown (priv->short_vendor, -1);
if (!strstr (pdown, vdown)) {
g_string_append (str, priv->short_vendor);
g_string_append_c (str, ' ');
{
gs_free char *pdown = g_ascii_strdown (short_product, -1);
gs_free char *vdown = g_ascii_strdown (priv->short_vendor, -1);
if (!strstr (pdown, vdown))
priv->description = g_strconcat (priv->short_vendor, " ", short_product, NULL);
else
priv->description = g_steal_pointer (&short_product);
}
g_free (pdown);
g_free (vdown);
g_string_append (str, priv->short_product);
priv->description = g_string_free (str, FALSE);
}
static const char *
@ -1580,7 +1611,7 @@ get_short_vendor (NMDevice *device)
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->description)
get_description (device);
ensure_description (device);
return priv->short_vendor;
}
@ -1604,7 +1635,7 @@ nm_device_get_description (NMDevice *device)
priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->description)
get_description (device);
ensure_description (device);
return priv->description;
}

View file

@ -397,3 +397,141 @@ nm_g_object_set_property (GObject *object,
}
/*****************************************************************************/
static void
_str_append_escape (GString *s, char ch)
{
g_string_append_c (s, '\\');
g_string_append_c (s, '0' + ((((guchar) ch) >> 6) & 07));
g_string_append_c (s, '0' + ((((guchar) ch) >> 3) & 07));
g_string_append_c (s, '0' + ( ((guchar) ch) & 07));
}
/**
* nm_utils_str_utf8safe_escape:
* @str: NUL terminated input string, possibly in utf-8 encoding
* @flags: #NMUtilsStrUtf8SafeFlags flags
* @to_free: (out): return the pointer location of the string
* if a copying was necessary.
*
* Returns the possible non-UTF-8 NUL terminated string @str
* and uses backslash escaping (C escaping, like g_strescape())
* to sanitize non UTF-8 characters. The result is valid
* UTF-8.
*
* The operation can be reverted with g_strcompress() or
* nm_utils_str_utf8safe_unescape().
*
* Depending on @flags, valid UTF-8 characters are not escaped at all
* (except the escape character '\\'). This is the difference to g_strescape(),
* which escapes all non-ASCII characters. This allows to pass on
* valid UTF-8 characters as-is and can be directly shown to the user
* as UTF-8 -- with exception of the backslash escape character,
* invalid UTF-8 sequences, and other (depending on @flags).
*
* Returns: the escaped input string, as valid UTF-8. If no escaping
* is necessary, it returns the input @str. Otherwise, an allocated
* string @to_free is returned which must be freed by the caller
* with g_free. The escaping can be reverted by g_strcompress().
**/
const char *
nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
{
const char *p = NULL;
GString *s;
g_return_val_if_fail (to_free, NULL);
*to_free = NULL;
if (!str || !str[0])
return str;
if ( g_utf8_validate (str, -1, &p)
&& !NM_STRCHAR_ANY (str, ch,
( ch == '\\' \
|| ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \
&& ch < ' ') \
|| ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \
&& ((guchar) ch) >= 127))))
return str;
s = g_string_sized_new ((p - str) + strlen (p) + 5);
do {
for (; str < p; str++) {
char ch = str[0];
if (ch == '\\')
g_string_append (s, "\\\\");
else if ( ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \
&& ch < ' ') \
|| ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \
&& ((guchar) ch) >= 127))
_str_append_escape (s, ch);
else
g_string_append_c (s, ch);
}
if (p[0] == '\0')
break;
_str_append_escape (s, p[0]);
str = &p[1];
g_utf8_validate (str, -1, &p);
} while (TRUE);
*to_free = g_string_free (s, FALSE);
return *to_free;
}
const char *
nm_utils_str_utf8safe_unescape (const char *str, char **to_free)
{
g_return_val_if_fail (to_free, NULL);
if (!str || !strchr (str, '\\')) {
*to_free = NULL;
return str;
}
return (*to_free = g_strcompress (str));
}
/**
* nm_utils_str_utf8safe_escape_cp:
* @str: NUL terminated input string, possibly in utf-8 encoding
* @flags: #NMUtilsStrUtf8SafeFlags flags
*
* Like nm_utils_str_utf8safe_escape(), except the returned value
* is always a copy of the input and must be freed by the caller.
*
* Returns: the escaped input string in UTF-8 encoding. The returned
* value should be freed with g_free().
* The escaping can be reverted by g_strcompress().
**/
char *
nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags)
{
char *s;
nm_utils_str_utf8safe_escape (str, flags, &s);
return s ?: g_strdup (str);
}
char *
nm_utils_str_utf8safe_unescape_cp (const char *str)
{
return str ? g_strcompress (str) : NULL;
}
char *
nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags)
{
char *str_to_free;
nm_utils_str_utf8safe_escape (str, flags, &str_to_free);
if (str_to_free) {
g_free (str);
return str_to_free;
}
return str;
}

View file

@ -97,4 +97,20 @@ gboolean nm_g_object_set_property (GObject *object,
/*****************************************************************************/
typedef enum {
NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002,
} NMUtilsStrUtf8SafeFlags;
const char *nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free);
const char *nm_utils_str_utf8safe_unescape (const char *str, char **to_free);
char *nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags);
char *nm_utils_str_utf8safe_unescape_cp (const char *str);
char *nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags);
/*****************************************************************************/
#endif /* __NM_SHARED_UTILS_H__ */

View file

@ -67,8 +67,9 @@ nm_udev_utils_property_decode (const char *uproperty, char **to_free)
if ( p[0] == '\\'
&& p[1] == 'x'
&& (a = g_ascii_xdigit_value (p[2])) >= 0
&& (b = g_ascii_xdigit_value (p[3])) >= 0) {
if (!unescaped) {
&& (b = g_ascii_xdigit_value (p[3])) >= 0
&& (a || b)) {
if (!n) {
gssize l = p - uproperty;
unescaped = g_malloc (l + strlen (p) + 1 - 3);
@ -84,11 +85,12 @@ nm_udev_utils_property_decode (const char *uproperty, char **to_free)
}
}
if (!unescaped) {
if (!n) {
*to_free = NULL;
return uproperty;
}
*n++ = '\0';
return (*to_free = unescaped);
}

View file

@ -2463,7 +2463,7 @@ device_link_changed (NMDevice *self)
info = *pllink;
udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex);
if (udi && g_strcmp0 (udi, priv->udi)) {
if (udi && !nm_streq0 (udi, priv->udi)) {
/* Update UDI to what udev gives us */
g_free (priv->udi);
priv->udi = g_strdup (udi);
@ -2844,7 +2844,7 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
g_return_if_fail (plink != NULL);
udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex);
if (udi && !g_strcmp0 (udi, priv->udi)) {
if (udi && !nm_streq0 (udi, priv->udi)) {
g_free (priv->udi);
priv->udi = g_strdup (udi);
_notify (self, PROP_UDI);
@ -13839,14 +13839,11 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_UDI:
if (g_value_get_string (value)) {
g_free (priv->udi);
priv->udi = g_value_dup_string (value);
}
/* construct-only */
priv->udi = g_value_dup_string (value);
break;
case PROP_IFACE:
/* construct-only */
g_return_if_fail (!priv->iface);
priv->iface = g_value_dup_string (value);
break;
case PROP_DRIVER:
@ -13941,28 +13938,43 @@ get_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_UDI:
g_value_set_string (value, priv->udi);
/* UDI is (depending on the device type) a path to sysfs and can contain
* non-UTF-8.
* ip link add name $'d\xccf\\c' type dummy */
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (priv->udi,
NM_UTILS_STR_UTF8_SAFE_FLAG_NONE));
break;
case PROP_IFACE:
g_value_set_string (value, priv->iface);
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (priv->iface,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
break;
case PROP_IP_IFACE:
if (ip_config_valid (priv->state))
g_value_set_string (value, nm_device_get_ip_iface (self));
else
if (ip_config_valid (priv->state)) {
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (nm_device_get_ip_iface (self),
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
} else
g_value_set_string (value, NULL);
break;
case PROP_IFINDEX:
g_value_set_int (value, priv->ifindex);
break;
case PROP_DRIVER:
g_value_set_string (value, priv->driver);
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (priv->driver,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
break;
case PROP_DRIVER_VERSION:
g_value_set_string (value, priv->driver_version);
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (priv->driver_version,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
break;
case PROP_FIRMWARE_VERSION:
g_value_set_string (value, priv->firmware_version);
g_value_take_string (value,
nm_utils_str_utf8safe_escape_cp (priv->firmware_version,
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL));
break;
case PROP_CAPABILITIES:
g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK));
@ -14159,7 +14171,7 @@ nm_device_class_init (NMDeviceClass *klass)
obj_properties[PROP_UDI] =
g_param_spec_string (NM_DEVICE_UDI, "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IFACE] =
g_param_spec_string (NM_DEVICE_IFACE, "", "",