]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: make probing data structures more dynamic
authorOndrej Oprala <ooprala@redhat.com>
Tue, 3 Feb 2015 15:30:15 +0000 (16:30 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 24 Feb 2015 09:22:37 +0000 (10:22 +0100)
* replace static probing result array with list
* use allocated buffers for probing result variables

[kzak@redhat.com: - rename some functions
                  - clean up \0 terminator usage in variables
                  - remove never used code to convert UUID to lower-case
                  - remove possible memory leaks on errors]

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
libblkid/src/blkidP.h
libblkid/src/encode.c
libblkid/src/partitions/partitions.c
libblkid/src/probe.c
libblkid/src/superblocks/superblocks.c

index fbf4e719b175c4030f1ffc03076f0f7fb8950bdb..4d440800e61d26931cde2a012af063d9f65a3e14 100644 (file)
@@ -118,24 +118,14 @@ struct blkid_chaindrv {
 /*
  * Low-level probe result
  */
-#define BLKID_PROBVAL_BUFSIZ   128
-
-#define BLKID_NVALS_SUBLKS     18
-#define BLKID_NVALS_TOPLGY     5
-#define BLKID_NVALS_PARTS      13
-
-/* Max number of all values in probing result */
-#define BLKID_NVALS             (BLKID_NVALS_SUBLKS + \
-                                BLKID_NVALS_TOPLGY + \
-                                BLKID_NVALS_PARTS)
-
 struct blkid_prval
 {
-       const char      *name;                  /* value name */
-       unsigned char   data[BLKID_PROBVAL_BUFSIZ]; /* value data */
-       size_t          len;                    /* length of value data */
+       const char      *name;          /* value name */
+       unsigned char   *data;          /* value data */
+       size_t          len;            /* length of value data */
 
        struct blkid_chain      *chain;         /* owner */
+       struct list_head        prvals;         /* list of results */
 };
 
 /*
@@ -208,8 +198,7 @@ struct blkid_struct_probe
        struct blkid_chain      chains[BLKID_NCHAINS];  /* array of chains */
        struct blkid_chain      *cur_chain;             /* current chain */
 
-       struct blkid_prval      vals[BLKID_NVALS];      /* results */
-       int                     nvals;          /* number of assigned vals */
+       struct list_head        vals;           /* results */
 
        struct blkid_struct_probe *parent;      /* for clones */
        struct blkid_struct_probe *disk_probe;  /* whole-disk probing */
@@ -432,8 +421,7 @@ extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn
                        __attribute__((nonnull));
 extern int blkid_probe_chain_copy_vals(blkid_probe pr,
                                       struct blkid_chain *chn,
-                                      struct blkid_prval *vals,
-                                      int nvals)
+                                      struct list_head *vals)
                        __attribute__((nonnull));
 
 extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr,
@@ -441,17 +429,19 @@ extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr,
                        __attribute__((nonnull))
                        __attribute__((warn_unused_result));
 
-extern int blkid_probe_reset_last_value(blkid_probe pr)
-                       __attribute__((nonnull));
+extern void blkid_probe_free_val(struct blkid_prval *v);
+
+
 extern void blkid_probe_append_vals(blkid_probe pr,
-                                   struct blkid_prval *vals,
-                                   int nvals)
+                                   struct list_head *vals)
                        __attribute__((nonnull));
 
 extern struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
                        __attribute__((nonnull))
                        __attribute__((warn_unused_result));
 
+extern struct blkid_prval *blkid_probe_last_value(blkid_probe pr);
+
 extern struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
                        __attribute__((nonnull))
                        __attribute__((warn_unused_result));
@@ -475,9 +465,14 @@ extern void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn
                        __attribute__((nonnull))
                        __attribute__((warn_unused_result));
 
+extern struct blkid_prval *blkid_probe_new_val(void)
+                       __attribute__((warn_unused_result));
 extern int blkid_probe_set_value(blkid_probe pr, const char *name,
                                unsigned char *data, size_t len)
                        __attribute__((nonnull));
+extern int blkid_probe_value_set_data(struct blkid_prval *v,
+                               unsigned char *data, size_t len)
+                       __attribute__((nonnull));
 
 extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
                                const char *fmt, va_list ap)
@@ -535,6 +530,7 @@ extern void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t
                (blkid_bmp_nwords(max_items) * sizeof(unsigned long))
 
 /* encode.c */
+extern unsigned char *blkid_encode_alloc(size_t count, size_t *reslen);
 extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
                                const unsigned char *src, size_t count)
                        __attribute__((nonnull));
index ff57be4cb3b080b4da1a5542dcdd46d0f7d7ff8a..466e4540f9c768d266941e1c16590491e798cb87 100644 (file)
@@ -268,6 +268,12 @@ size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
        return j;
 }
 
+unsigned char *blkid_encode_alloc(size_t count, size_t *reslen)
+{
+       *reslen = (count * 3) + 1;
+       return calloc(1, *reslen);
+}
+
 /**
  * blkid_encode_string:
  * @str: input string to be encoded
index 4853f97e29fc58b1664d8a41c9f7f424abd1cd89..b28dfbd57a5cd47609bdf5cf114206be95124baf 100644 (file)
@@ -1098,11 +1098,18 @@ int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
                return 0;
 
        v = blkid_probe_assign_value(pr, "PTUUID");
+       if (!v)
+               return -ENOMEM;
 
-       blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
        v->len = 37;
+       v->data = calloc(1, v->len);
+       if (v->data) {
+               blkid_unparse_uuid(uuid, (char *) v->data, v->len);
+               return 0;
+       }
 
-       return 0;
+       blkid_probe_free_val(v);
+       return -ENOMEM;
 }
 
 /* set PTUUID variable for non-binary API for tables where
@@ -1110,27 +1117,14 @@ int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
 int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str)
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
-       struct blkid_prval *v;
-       size_t len;
 
        if (chn->binary || !str || !*str)
                return 0;
 
-       len = strlen((char *) str);
-       if (len > BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ;
-
-       v = blkid_probe_assign_value(pr, "PTUUID");
-       if (v) {
-               if (len == BLKID_PROBVAL_BUFSIZ)
-                       len--;          /* make a space for \0 */
+       if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1))
+               return -ENOMEM;
 
-               memcpy((char *) v->data, str, len);
-               v->data[len] = '\0';
-               v->len = len + 1;
-               return 0;
-       }
-       return -1;
+       return 0;
 }
 
 /**
index 70e882ac9b0f724389ce01c4d9477b7c0881f471..2f4e7c90e3360c6d14725ba14cb22bcae1c78969 100644 (file)
 #include "all-io.h"
 #include "sysfs.h"
 #include "strutils.h"
+#include "list.h"
 
 /* chains */
 extern const struct blkid_chaindrv superblocks_drv;
@@ -128,6 +129,7 @@ static const struct blkid_chaindrv *chains_drvs[] = {
        [BLKID_CHAIN_PARTS] = &partitions_drv
 };
 
+static struct blkid_prval *blkid_probe_new_value(void);
 static void blkid_probe_reset_vals(blkid_probe pr);
 static void blkid_probe_reset_buffer(blkid_probe pr);
 
@@ -155,6 +157,7 @@ blkid_probe blkid_new_probe(void)
                pr->chains[i].enabled = chains_drvs[i]->dflt_enabled;
        }
        INIT_LIST_HEAD(&pr->buffers);
+       INIT_LIST_HEAD(&pr->vals);
        return pr;
 }
 
@@ -265,29 +268,34 @@ void blkid_free_probe(blkid_probe pr)
        free(pr);
 }
 
+void blkid_probe_free_val(struct blkid_prval *v)
+{
+       if (!v)
+               return;
+
+       list_del(&v->prvals);
+       free(v->data);
+       free(v);
+}
 
 /*
  * Removes chain values from probing result.
  */
 void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn)
 {
-       int nvals = pr->nvals;
-       int i, x;
 
-       for (x = 0, i = 0; i < pr->nvals; i++) {
-               struct blkid_prval *v = &pr->vals[i];
+       struct list_head *p, *pnext;
 
-               if (v->chain != chn && x == i) {
-                       x++;
-                       continue;
-               }
-               if (v->chain == chn) {
-                       --nvals;
-                       continue;
-               }
-               memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval));
+       if (!pr || list_empty(&pr->vals))
+               return;
+
+       list_for_each_safe(p, pnext, &pr->vals) {
+               struct blkid_prval *v = list_entry(p,
+                                               struct blkid_prval, prvals);
+
+               if (v->chain == chn)
+                       blkid_probe_free_val(v);
        }
-       pr->nvals = nvals;
 }
 
 static void blkid_probe_chain_reset_position(struct blkid_chain *chn)
@@ -296,42 +304,56 @@ static void blkid_probe_chain_reset_position(struct blkid_chain *chn)
                chn->idx = -1;
 }
 
+static struct blkid_prval *blkid_probe_deep_copy_val(struct blkid_prval *dest,
+                                               struct blkid_prval *src)
+{
+       memcpy(dest, src, sizeof(struct blkid_prval));
+
+       dest->data = malloc(src->len);
+       if (!dest->data)
+               return NULL;
+
+       memcpy(dest->data, src->data, src->len);
+
+       INIT_LIST_HEAD(&dest->prvals);
+
+       return dest;
+}
+
 /*
- * Copies chain values from probing result to @vals, the max size of @vals is
- * @nvals and returns real number of values.
+ * Copies chain values from probing result to @vals.
  */
 int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn,
-               struct blkid_prval *vals, int nvals)
+               struct list_head *vals)
 {
-       int i, x;
+       struct list_head *p;
+       struct blkid_prval *new_v, *v;
 
-       for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) {
-               struct blkid_prval *v = &pr->vals[i];
+       list_for_each(p, &pr->vals) {
+
+               v = list_entry(p, struct blkid_prval, prvals);
+
+               new_v = blkid_probe_new_value();
+               if (!new_v)
+                       break;
 
                if (v->chain != chn)
                        continue;
-               memcpy(&vals[x++], v, sizeof(struct blkid_prval));
+
+               if (!blkid_probe_deep_copy_val(new_v, v))
+                       break;
+
+               list_add_tail(&new_v->prvals, vals);
        }
-       return x;
+       return 0;
 }
 
 /*
  * Appends values from @vals to the probing result
  */
-void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals)
+void blkid_probe_append_vals(blkid_probe pr, struct list_head *vals)
 {
-       int i = 0;
-
-       while (i < nvals && pr->nvals < BLKID_NVALS) {
-               memcpy(&pr->vals[pr->nvals++], &vals[i++],
-                               sizeof(struct blkid_prval));
-       }
-}
-
-static void blkid_probe_reset_vals(blkid_probe pr)
-{
-       memset(pr->vals, 0, sizeof(pr->vals));
-       pr->nvals = 0;
+       list_splice(vals, &pr->vals);
 }
 
 struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
@@ -615,7 +637,6 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
        return off ? bf->data + (off - bf->off) : bf->data;
 }
 
-
 static void blkid_probe_reset_buffer(blkid_probe pr)
 {
        uint64_t read_ct = 0, len_ct = 0;
@@ -641,6 +662,22 @@ static void blkid_probe_reset_buffer(blkid_probe pr)
        INIT_LIST_HEAD(&pr->buffers);
 }
 
+static void blkid_probe_reset_vals(blkid_probe pr)
+{
+       if (!pr || list_empty(&pr->vals))
+               return;
+
+       DBG(LOWPROBE, ul_debug("resetting results pr=%p", pr));
+
+       while (!list_empty(&pr->vals)) {
+               struct blkid_prval *v = list_entry(pr->vals.next,
+                                               struct blkid_prval, prvals);
+               blkid_probe_free_val(v);
+       }
+
+       INIT_LIST_HEAD(&pr->vals);
+}
+
 /*
  * Small devices need a special care.
  */
@@ -1273,37 +1310,47 @@ struct blkid_prval *blkid_probe_assign_value(
                        blkid_probe pr, const char *name)
 {
        struct blkid_prval *v;
-
        if (!name)
                return NULL;
-       if (pr->nvals >= BLKID_NVALS)
+
+       v = blkid_probe_new_value();
+       if (!v)
                return NULL;
 
-       v = &pr->vals[pr->nvals];
        v->name = name;
        v->chain = pr->cur_chain;
-       pr->nvals++;
+       list_add_tail(&v->prvals, &pr->vals);
 
        DBG(LOWPROBE, ul_debug("assigning %s [%s]", name, v->chain->driver->name));
        return v;
 }
 
-int blkid_probe_reset_last_value(blkid_probe pr)
+static struct blkid_prval *blkid_probe_new_value(void)
 {
-       struct blkid_prval *v;
-
-       if (pr == NULL || pr->nvals == 0)
-               return -1;
+       struct blkid_prval *v = calloc(1, sizeof(struct blkid_prval));
+       if (!v)
+               return NULL;
 
-       v = &pr->vals[pr->nvals - 1];
+       INIT_LIST_HEAD(&v->prvals);
 
-       DBG(LOWPROBE, ul_debug("un-assigning %s [%s]", v->name, v->chain->driver->name));
+       return v;
+}
 
-       memset(v, 0, sizeof(struct blkid_prval));
-       pr->nvals--;
+/* Note that value data is always terminated by zero to keep things robust,
+ * this extra zero is not count to the value lenght. It's caller responsibility
+ * to set proper value lenght (for strings we count terminator to the lenght,
+ * for binary data it's without terminator).
+ */
+int blkid_probe_value_set_data(struct blkid_prval *v,
+               unsigned char *data, size_t len)
+{
+       v->data = calloc(1, len + 1);   /* always terminate by \0 */
 
+       if (!v->data)
+               return -ENOMEM;
+       memcpy(v->data, data, len);
+       v->len = len;
        return 0;
-
 }
 
 int blkid_probe_set_value(blkid_probe pr, const char *name,
@@ -1311,16 +1358,11 @@ int blkid_probe_set_value(blkid_probe pr, const char *name,
 {
        struct blkid_prval *v;
 
-       if (len > BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ;
-
        v = blkid_probe_assign_value(pr, name);
        if (!v)
                return -1;
 
-       memcpy(v->data, data, len);
-       v->len = len;
-       return 0;
+       return blkid_probe_value_set_data(v, data, len);
 }
 
 int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
@@ -1331,13 +1373,13 @@ int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
 
        v = blkid_probe_assign_value(pr, name);
        if (!v)
-               return -1;
+               return -ENOMEM;
 
-       len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
+       len = vasprintf((char **) &v->data, fmt, ap);
 
-       if (len <= 0 || (size_t) len >= sizeof(v->data)) {
-               blkid_probe_reset_last_value(pr);
-               return -1;
+       if (len <= 0) {
+               blkid_probe_free_val(v);
+               return len == 0 ? -EINVAL : -ENOMEM;
        }
        v->len = len + 1;
        return 0;
@@ -1586,9 +1628,14 @@ blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
  */
 int blkid_probe_numof_values(blkid_probe pr)
 {
+       int i = 0;
+       struct list_head *p;
        if (!pr)
                return -1;
-       return pr->nvals;
+
+       list_for_each(p, &pr->vals)
+               ++i;
+       return i;
 }
 
 /**
@@ -1662,23 +1709,41 @@ int blkid_probe_has_value(blkid_probe pr, const char *name)
        return 0;
 }
 
+struct blkid_prval *blkid_probe_last_value(blkid_probe pr)
+{
+       if (!pr || list_empty(&pr->vals))
+               return NULL;
+
+       return list_last_entry(&pr->vals, struct blkid_prval, prvals);
+}
+
+
 struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
 {
-       if (!pr || num < 0 || num >= pr->nvals)
+       int i = 0;
+       struct list_head *p;
+
+       if (!pr || num < 0)
                return NULL;
 
-       return &pr->vals[num];
+       list_for_each(p, &pr->vals) {
+               if (i++ != num)
+                       continue;
+               return list_entry(p, struct blkid_prval, prvals);
+       }
+       return NULL;
 }
 
 struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name)
 {
-       int i;
+       struct list_head *p;
 
-       if (!pr || !pr->nvals || !name)
+       if (!pr || list_empty(&pr->vals) || !name)
                return NULL;
 
-       for (i = 0; i < pr->nvals; i++) {
-               struct blkid_prval *v = &pr->vals[i];
+       list_for_each(p, &pr->vals) {
+               struct blkid_prval *v = list_entry(p, struct blkid_prval,
+                                               prvals);
 
                if (v->name && strcmp(name, v->name) == 0) {
                        DBG(LOWPROBE, ul_debug("returning %s value", v->name));
index 975181d4c50c6746c01aa0232052c159ea6f620e..8d381599e0aa0706220a837e851b0a2cffba5f08 100644 (file)
@@ -451,13 +451,14 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
  */
 static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
 {
-       struct blkid_prval vals[BLKID_NVALS_SUBLKS];
-       int nvals = BLKID_NVALS_SUBLKS;
+       struct list_head vals;
        int idx = -1;
        int count = 0;
        int intol = 0;
        int rc;
 
+       INIT_LIST_HEAD(&vals);
+
        if (pr->flags & BLKID_FL_NOSCAN_DEV)
                return BLKID_PROBE_NONE;
 
@@ -478,7 +479,7 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
 
                if (count == 1) {
                        /* save the first result */
-                       nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
+                       blkid_probe_chain_copy_vals(pr, chn, &vals);
                        idx = chn->idx;
                }
        }
@@ -498,7 +499,7 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
        if (idx != -1) {
                /* restore the first result */
                blkid_probe_chain_reset_vals(pr, chn);
-               blkid_probe_append_vals(pr, vals, nvals);
+               blkid_probe_append_vals(pr, &vals);
                chn->idx = idx;
        }
 
@@ -566,28 +567,28 @@ int blkid_probe_set_id_label(blkid_probe pr, const char *name,
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
+       int rc = 0;
 
        if (!(chn->flags & BLKID_SUBLKS_LABEL))
                return 0;
 
        v = blkid_probe_assign_value(pr, name);
        if (!v)
-               return -1;
+               return -ENOMEM;
 
-       if (len >= BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ - 1;                 /* make a space for \0 */
-
-       memcpy(v->data, data, len);
-       v->data[len] = '\0';
+       rc = blkid_probe_value_set_data(v, data, len);
+       if (!rc) {
+               /* remove white spaces */
+               v->len = blkid_rtrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       v->len = blkid_ltrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       return 0;
+       }
 
-       /* remove white spaces */
-       v->len = blkid_rtrim_whitespace(v->data) + 1;
-       if (v->len > 1)
-               v->len = blkid_ltrim_whitespace(v->data) + 1;
+       blkid_probe_free_val(v);
+       return rc;
 
-       if (v->len <= 1)
-               blkid_probe_reset_last_value(pr);               /* ignore empty */
-       return 0;
 }
 
 int blkid_probe_set_utf8_id_label(blkid_probe pr, const char *name,
@@ -595,50 +596,58 @@ int blkid_probe_set_utf8_id_label(blkid_probe pr, const char *name,
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
+       int rc = 0;
 
        if (!(chn->flags & BLKID_SUBLKS_LABEL))
                return 0;
 
        v = blkid_probe_assign_value(pr, name);
        if (!v)
-               return -1;
+               return -ENOMEM;
 
-       blkid_encode_to_utf8(enc, v->data, sizeof(v->data), data, len);
-       v->len = blkid_rtrim_whitespace(v->data) + 1;
-       if (v->len > 1)
-               v->len = blkid_ltrim_whitespace(v->data) + 1;
+       v->data = blkid_encode_alloc(len, &v->len);
+       if (!v->data)
+               rc = -ENOMEM;
 
-       if (v->len <= 1)
-               blkid_probe_reset_last_value(pr);
-       return 0;
+       if (!rc) {
+               blkid_encode_to_utf8(enc, v->data, v->len, data, len);
+               v->len = blkid_rtrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       v->len = blkid_ltrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       return 0;
+       }
+
+       blkid_probe_free_val(v);
+       return rc;
 }
 
 int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
-       if (len > BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ;
+       int rc = 0;
 
        if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
-           blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
-               return -1;
+           (rc = blkid_probe_set_value(pr, "LABEL_RAW", label, len)) < 0)
+               return rc;
+
        if (!(chn->flags & BLKID_SUBLKS_LABEL))
                return 0;
+
        v = blkid_probe_assign_value(pr, "LABEL");
        if (!v)
-               return -1;
-
-       if (len == BLKID_PROBVAL_BUFSIZ)
-               len--;                          /* make a space for \0 */
+               return -ENOMEM;
 
-       memcpy(v->data, label, len);
-       v->data[len] = '\0';
+       rc = blkid_probe_value_set_data(v, label, len);
+       if (!rc) {
+               v->len = blkid_rtrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       return 0;
+       }
 
-       v->len = blkid_rtrim_whitespace(v->data) + 1;
-       if (v->len == 1)
-               blkid_probe_reset_last_value(pr);
-       return 0;
+       blkid_probe_free_val(v);
+       return rc;
 }
 
 int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
@@ -646,39 +655,47 @@ int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
+       int rc = 0;
 
        if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
-           blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
-               return -1;
+           (rc = blkid_probe_set_value(pr, "LABEL_RAW", label, len)) < 0)
+               return rc;
+
        if (!(chn->flags & BLKID_SUBLKS_LABEL))
                return 0;
+
        v = blkid_probe_assign_value(pr, "LABEL");
        if (!v)
-               return -1;
+               return -ENOMEM;
 
-       blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
-       v->len = blkid_rtrim_whitespace(v->data) + 1;
-       if (v->len == 1)
-               blkid_probe_reset_last_value(pr);
-       return 0;
+       v->data = blkid_encode_alloc(len, &v->len);
+       if (!v->data)
+               rc = -ENOMEM;
+       if (!rc) {
+               blkid_encode_to_utf8(enc, v->data, v->len, label, len);
+               v->len = blkid_rtrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       return 0;
+       }
+
+       blkid_probe_free_val(v);
+       return rc;
 }
 
 int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
                                size_t len, const char *fmt, ...)
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
-       int rc = -1;
        va_list ap;
-
-       if (len > BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ;
+       int rc = 0;
 
        if (blkid_uuid_is_empty(uuid, len))
                return 0;
 
        if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
-           blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
-               return -1;
+           (rc = blkid_probe_set_value(pr, "UUID_RAW", uuid, len)) < 0)
+               return rc;
+
        if (!(chn->flags & BLKID_SUBLKS_UUID))
                return 0;
 
@@ -686,17 +703,6 @@ int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
        rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
        va_end(ap);
 
-       /* convert to lower case (..be paranoid) */
-       if (!rc) {
-               size_t i;
-               struct blkid_prval *v = __blkid_probe_get_value(pr,
-                                               blkid_probe_numof_values(pr));
-               if (v) {
-                       for (i = 0; i < v->len; i++)
-                               if (v->data[i] >= 'A' && v->data[i] <= 'F')
-                                       v->data[i] = (v->data[i] - 'A') + 'a';
-               }
-       }
        return rc;
 }
 
@@ -705,31 +711,34 @@ int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
+       int rc = 0;
 
        if (str == NULL || *str == '\0')
-               return -1;
+               return -EINVAL;
+
        if (!len)
                len = strlen((char *) str);
-       if (len > BLKID_PROBVAL_BUFSIZ)
-               len = BLKID_PROBVAL_BUFSIZ;
 
        if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
-           blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
-               return -1;
+           (rc = blkid_probe_set_value(pr, "UUID_RAW", str, len)) < 0)
+               return rc;
+
        if (!(chn->flags & BLKID_SUBLKS_UUID))
                return 0;
 
        v = blkid_probe_assign_value(pr, "UUID");
-       if (v) {
-               if (len == BLKID_PROBVAL_BUFSIZ)
-                       len--;          /* make a space for \0 */
-
-               memcpy((char *) v->data, str, len);
-               v->data[len] = '\0';
-               v->len = len + 1;
-               return 0;
+       if (!v)
+               rc= -ENOMEM;
+       if (!rc)
+               rc = blkid_probe_value_set_data(v, str, len);
+       if (!rc) {
+               v->len = blkid_rtrim_whitespace(v->data) + 1;
+               if (v->len > 1)
+                       return 0;
        }
-       return -1;
+
+       blkid_probe_free_val(v);
+       return rc;
 }
 
 /* default _set_uuid function to set DCE UUIDs */
@@ -737,14 +746,16 @@ int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *nam
 {
        struct blkid_chain *chn = blkid_probe_get_chain(pr);
        struct blkid_prval *v;
+       int rc = 0;
 
        if (blkid_uuid_is_empty(uuid, 16))
                return 0;
 
        if (!name) {
                if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
-                   blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
-                       return -1;
+                   (rc = blkid_probe_set_value(pr, "UUID_RAW", uuid, 16)) < 0)
+                       return rc;
+
                if (!(chn->flags & BLKID_SUBLKS_UUID))
                        return 0;
 
@@ -752,10 +763,21 @@ int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *nam
        } else
                v = blkid_probe_assign_value(pr, name);
 
-       blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+       if (!v)
+               return -ENOMEM;
+
        v->len = 37;
+       v->data = calloc(1, v->len);
+       if (!v->data)
+               rc = -ENOMEM;
 
-       return 0;
+       if (!rc) {
+               blkid_unparse_uuid(uuid, (char *) v->data, v->len);
+               return 0;
+       }
+
+       blkid_probe_free_val(v);
+       return rc;
 }
 
 int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)