]> err.no Git - util-linux/commitdiff
blkid: add udev string encoding routines
authorKarel Zak <kzak@redhat.com>
Wed, 14 Jan 2009 00:52:11 +0000 (01:52 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 11 Feb 2009 22:21:51 +0000 (23:21 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libs/blkid/src/Makefile.am
libs/blkid/src/blkid.h
libs/blkid/src/blkid.sym
libs/blkid/src/encode.c [new file with mode: 0644]
libs/blkid/src/probers/btrfs.c

index cf43a734f9a56fd0ab95625e5e172d9a4b2ff20e..e21fbc20627a4cb463b5da7e7e1adc97ae56b878 100644 (file)
@@ -8,7 +8,7 @@ AM_CPPFLAGS += -I$(top_builddir)/libs/blkid/src
 lib_LIBRARIES = libblkid.a
 libblkid_a_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c  \
                     probe.c read.c resolve.c save.c tag.c version.c verify.c \
-                    blkid.h blkidP.h list.h probers/probers.h \
+                    encode.c blkid.h blkidP.h list.h probers/probers.h \
                     $(top_srcdir)/lib/blkdev.c \
                     $(top_srcdir)/lib/linux_version.c \
                     $(top_srcdir)/lib/md5.c
index be6f7e06fa1009b457ff6a8f993fc810b3db9d2c..26f04b897673cf9cd6c6ea623cc776eafc4aa65e 100644 (file)
@@ -111,7 +111,9 @@ extern int blkid_parse_version_string(const char *ver_string);
 extern int blkid_get_library_version(const char **ver_string,
                                     const char **date_string);
 
-
+/* encode.c */
+extern int blkid_encode_string(const char *str, char *str_enc, size_t len);
+extern int blkid_safe_string(const char *str, char *str_safe, size_t len);
 
 /* probe.c */
 extern int blkid_known_fstype(const char *fstype);
index 51bdde9749093b02c020d8269f2d0ce598ee7c31..105f3ff9b52936c0c01d36c88972c72775a3e45f 100644 (file)
@@ -7,6 +7,7 @@
        blkid_devno_to_devname;
        blkid_dev_set_search;
        blkid_do_probe;
+       blkid_encode_string;
        blkid_find_dev_with_tag;
        blkid_free_probe;
        blkid_gc_cache;
@@ -34,6 +35,7 @@
        blkid_probe_set_request;
        blkid_put_cache;
        blkid_reset_probe;
+       blkid_safe_string;
        blkid_tag_iterate_begin;
        blkid_tag_iterate_end;
        blkid_tag_next;
diff --git a/libs/blkid/src/encode.c b/libs/blkid/src/encode.c
new file mode 100644 (file)
index 0000000..0c00ec9
--- /dev/null
@@ -0,0 +1,288 @@
+
+/*
+ * encode.c - string convertion routines (mostly for compatibility with
+ *            udev/volume_id)
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "blkdev.h"
+#include "blkidP.h"
+
+#define UDEV_ALLOWED_CHARS_INPUT               "/ $%?,"
+
+/* count of characters used to encode one unicode char */
+static int utf8_encoded_expected_len(const char *str)
+{
+       unsigned char c = (unsigned char)str[0];
+
+       if (c < 0x80)
+               return 1;
+       if ((c & 0xe0) == 0xc0)
+               return 2;
+       if ((c & 0xf0) == 0xe0)
+               return 3;
+       if ((c & 0xf8) == 0xf0)
+               return 4;
+       if ((c & 0xfc) == 0xf8)
+               return 5;
+       if ((c & 0xfe) == 0xfc)
+               return 6;
+       return 0;
+}
+
+/* decode one unicode char */
+static int utf8_encoded_to_unichar(const char *str)
+{
+       int unichar;
+       int len;
+       int i;
+
+       len = utf8_encoded_expected_len(str);
+       switch (len) {
+       case 1:
+               return (int)str[0];
+       case 2:
+               unichar = str[0] & 0x1f;
+               break;
+       case 3:
+               unichar = (int)str[0] & 0x0f;
+               break;
+       case 4:
+               unichar = (int)str[0] & 0x07;
+               break;
+       case 5:
+               unichar = (int)str[0] & 0x03;
+               break;
+       case 6:
+               unichar = (int)str[0] & 0x01;
+               break;
+       default:
+               return -1;
+       }
+
+       for (i = 1; i < len; i++) {
+               if (((int)str[i] & 0xc0) != 0x80)
+                       return -1;
+               unichar <<= 6;
+               unichar |= (int)str[i] & 0x3f;
+       }
+
+       return unichar;
+}
+
+/* expected size used to encode one unicode char */
+static int utf8_unichar_to_encoded_len(int unichar)
+{
+       if (unichar < 0x80)
+               return 1;
+       if (unichar < 0x800)
+               return 2;
+       if (unichar < 0x10000)
+               return 3;
+       if (unichar < 0x200000)
+               return 4;
+       if (unichar < 0x4000000)
+               return 5;
+       return 6;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+       if (unichar > 0x10ffff)
+               return 0;
+       if ((unichar & 0xfffff800) == 0xd800)
+               return 0;
+       if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+               return 0;
+       if ((unichar & 0xffff) == 0xffff)
+               return 0;
+       return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+static int utf8_encoded_valid_unichar(const char *str)
+{
+       int len;
+       int unichar;
+       int i;
+
+       len = utf8_encoded_expected_len(str);
+       if (len == 0)
+               return -1;
+
+       /* ascii is valid */
+       if (len == 1)
+               return 1;
+
+       /* check if expected encoded chars are available */
+       for (i = 0; i < len; i++)
+               if ((str[i] & 0x80) != 0x80)
+                       return -1;
+
+       unichar = utf8_encoded_to_unichar(str);
+
+       /* check if encoded length matches encoded value */
+       if (utf8_unichar_to_encoded_len(unichar) != len)
+               return -1;
+
+       /* check if value has valid range */
+       if (!utf8_unichar_valid_range(unichar))
+               return -1;
+
+       return len;
+}
+
+static int replace_whitespace(const char *str, char *to, size_t len)
+{
+       size_t i, j;
+
+       /* strip trailing whitespace */
+       len = strnlen(str, len);
+       while (len && isspace(str[len-1]))
+               len--;
+
+       /* strip leading whitespace */
+       i = 0;
+       while (isspace(str[i]) && (i < len))
+               i++;
+
+       j = 0;
+       while (i < len) {
+               /* substitute multiple whitespace with a single '_' */
+               if (isspace(str[i])) {
+                       while (isspace(str[i]))
+                               i++;
+                       to[j++] = '_';
+               }
+               to[j++] = str[i++];
+       }
+       to[j] = '\0';
+       return 0;
+}
+
+static int is_whitelisted(char c, const char *white)
+{
+       if ((c >= '0' && c <= '9') ||
+           (c >= 'A' && c <= 'Z') ||
+           (c >= 'a' && c <= 'z') ||
+           strchr("#+-.:=@_", c) != NULL ||
+           (white != NULL && strchr(white, c) != NULL))
+               return 1;
+       return 0;
+}
+
+/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
+static int replace_chars(char *str, const char *white)
+{
+       size_t i = 0;
+       int replaced = 0;
+
+       while (str[i] != '\0') {
+               int len;
+
+               if (is_whitelisted(str[i], white)) {
+                       i++;
+                       continue;
+               }
+
+               /* accept hex encoding */
+               if (str[i] == '\\' && str[i+1] == 'x') {
+                       i += 2;
+                       continue;
+               }
+
+               /* accept valid utf8 */
+               len = utf8_encoded_valid_unichar(&str[i]);
+               if (len > 1) {
+                       i += len;
+                       continue;
+               }
+
+               /* if space is allowed, replace whitespace with ordinary space */
+               if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
+                       str[i] = ' ';
+                       i++;
+                       replaced++;
+                       continue;
+               }
+
+               /* everything else is replaced with '_' */
+               str[i] = '_';
+               i++;
+               replaced++;
+       }
+       return replaced;
+}
+
+/**
+ * blkid_encode_string:
+ * @str: input string to be encoded
+ * @str_enc: output string to store the encoded input string
+ * @len: maximum size of the output string, which may be
+ *       four times as long as the input string
+ *
+ * Encode all potentially unsafe characters of a string to the
+ * corresponding hex value prefixed by '\x'.
+ *
+ * Returns: 0 if the entire string was copied, non-zero otherwise.
+ **/
+int blkid_encode_string(const char *str, char *str_enc, size_t len)
+{
+       size_t i, j;
+
+       if (str == NULL || str_enc == NULL || len == 0)
+               return -1;
+
+       str_enc[0] = '\0';
+       for (i = 0, j = 0; str[i] != '\0'; i++) {
+               int seqlen;
+
+               seqlen = utf8_encoded_valid_unichar(&str[i]);
+               if (seqlen > 1) {
+                       memcpy(&str_enc[j], &str[i], seqlen);
+                       j += seqlen;
+                       i += (seqlen-1);
+               } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
+                       sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
+                       j += 4;
+               } else {
+                       str_enc[j] = str[i];
+                       j++;
+               }
+               if (j+3 >= len)
+                       goto err;
+       }
+       str_enc[j] = '\0';
+       return 0;
+err:
+       return -1;
+}
+
+/**
+ * blkid_safe_string:
+ * @str: input string
+ * @str_safe: output string
+ * @len: size of output string
+ *
+ * Allows plain ascii, hex-escaping and valid utf8. Replaces all whitespaces
+ * with '_'.
+ */
+int blkid_safe_string(const char *str, char *str_safe, size_t len)
+{
+       replace_whitespace(str, str_safe, sizeof(len));
+       replace_chars(str_safe, UDEV_ALLOWED_CHARS_INPUT);
+       return 0;
+}
index b7590f78b402e9c4fc75b4f0850f22f15a7405f7..3205e3d977972dcdacec3ade0a065a5f3656452b 100644 (file)
@@ -73,7 +73,7 @@ static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag)
                                sizeof(bfs->label));
 
        blkid_probe_set_uuid(pr, bfs->fsid);
-       blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "SUB_UUID");
+       blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB");
 
        return 0;
 }