#include "strutils.h"
#include "mountP.h"
+#include "buffer.h"
/*
* Option location
return mnt_optstr_parse_next(optstr, name, namesz, value, valuesz);
}
-static int __mnt_optstr_append_option(char **optstr,
- const char *name, size_t nsz,
- const char *value, size_t vsz)
+static int __buffer_append_option(struct ul_buffer *buf,
+ const char *name, size_t namesz,
+ const char *val, size_t valsz)
{
- char *p;
- size_t sz, osz;
-
- assert(name);
- assert(*name);
- assert(nsz);
- assert(optstr);
-
- osz = *optstr ? strlen(*optstr) : 0;
-
- sz = osz + nsz + 1; /* 1: '\0' */
- if (osz)
- sz++; /* ',' options separator */
- if (value)
- sz += vsz + 1; /* 1: '=' */
-
- p = realloc(*optstr, sz);
- if (!p)
- return -ENOMEM;
- *optstr = p;
-
- if (osz) {
- p += osz;
- *p++ = ',';
- }
-
- memcpy(p, name, nsz);
- p += nsz;
+ int rc = 0;
- if (value) {
- *p++ = '=';
- memcpy(p, value, vsz);
- p += vsz;
+ if (!ul_buffer_is_empty(buf))
+ rc = ul_buffer_append_data(buf, ",", 1);
+ if (!rc)
+ rc = ul_buffer_append_data(buf, name, namesz);
+ if (val && !rc) {
+ /* we need to append '=' is value is empty string, see
+ * 727c689908c5e68c92aa1dd65e0d3bdb6d91c1e5 */
+ rc = ul_buffer_append_data(buf, "=", 1);
+ if (!rc && valsz)
+ rc = ul_buffer_append_data(buf, val, valsz);
}
- *p = '\0';
-
- return 0;
+ return rc;
}
/**
*/
int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
{
- size_t vsz, nsz;
+ struct ul_buffer buf = UL_INIT_BUFFER;
+ int rc;
+ size_t nsz, vsz, osz;
if (!optstr)
return -EINVAL;
return 0;
nsz = strlen(name);
+ osz = *optstr ? strlen(*optstr) : 0;
vsz = value ? strlen(value) : 0;
- return __mnt_optstr_append_option(optstr, name, nsz, value, vsz);
-}
+ ul_buffer_refer_string(&buf, *optstr);
+ ul_buffer_set_chunksize(&buf, osz + nsz + vsz + 3); /* to call realloc() only once */
+
+ rc = __buffer_append_option(&buf, name, nsz, value, vsz);
+ *optstr = ul_buffer_get_data(&buf);
+ return rc;
+}
/**
* mnt_optstr_prepend_option:
* @optstr: option string or NULL, returns a reallocated string
*/
int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value)
{
- int rc = 0;
- char *tmp;
+ struct ul_buffer buf = UL_INIT_BUFFER;
+ size_t nsz, vsz, osz;
+ int rc;
if (!optstr)
return -EINVAL;
if (!name || !*name)
return 0;
- tmp = *optstr;
- *optstr = NULL;
+ nsz = strlen(name);
+ osz = *optstr ? strlen(*optstr) : 0;
+ vsz = value ? strlen(value) : 0;
- rc = mnt_optstr_append_option(optstr, name, value);
- if (!rc && tmp && *tmp)
- rc = mnt_optstr_append_option(optstr, tmp, NULL);
- if (!rc) {
- free(tmp);
- return 0;
- }
+ ul_buffer_set_chunksize(&buf, osz + nsz + vsz + 3); /* to call realloc() only once */
- free(*optstr);
- *optstr = tmp;
+ rc = __buffer_append_option(&buf, name, nsz, value, vsz);
+ if (*optstr && !rc) {
+ rc = ul_buffer_append_data(&buf, ",", 1);
+ if (!rc)
+ rc = ul_buffer_append_data(&buf, *optstr, osz);
+ free(*optstr);
+ }
- DBG(OPTIONS, ul_debug("failed to prepend '%s[=%s]' to '%s'",
- name, value, *optstr));
+ *optstr = ul_buffer_get_data(&buf);
return rc;
}
int mnt_split_optstr(const char *optstr, char **user, char **vfs,
char **fs, int ignore_user, int ignore_vfs)
{
+ int rc = 0;
char *name, *val, *str = (char *) optstr;
- size_t namesz, valsz;
+ size_t namesz, valsz, chunsz;
struct libmnt_optmap const *maps[2];
+ struct ul_buffer xvfs = UL_INIT_BUFFER,
+ xfs = UL_INIT_BUFFER,
+ xuser = UL_INIT_BUFFER;
if (!optstr)
return -EINVAL;
maps[0] = mnt_get_builtin_optmap(MNT_LINUX_MAP);
maps[1] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
- if (vfs)
- *vfs = NULL;
- if (fs)
- *fs = NULL;
- if (user)
- *user = NULL;
+ chunsz = strlen(optstr) / 2;
while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
- int rc = 0;
+ struct ul_buffer *buf = NULL;
const struct libmnt_optmap *ent = NULL;
const struct libmnt_optmap *m =
mnt_optmap_get_entry(maps, 2, name, namesz, &ent);
if (ent && m && m == maps[0] && vfs) {
if (ignore_vfs && (ent->mask & ignore_vfs))
continue;
- rc = __mnt_optstr_append_option(vfs, name, namesz,
- val, valsz);
+ if (vfs)
+ buf = &xvfs;
} else if (ent && m && m == maps[1] && user) {
if (ignore_user && (ent->mask & ignore_user))
continue;
- rc = __mnt_optstr_append_option(user, name, namesz,
- val, valsz);
- } else if (!m && fs)
- rc = __mnt_optstr_append_option(fs, name, namesz,
- val, valsz);
- if (rc) {
- if (vfs) {
- free(*vfs);
- *vfs = NULL;
- }
- if (fs) {
- free(*fs);
- *fs = NULL;
- }
- if (user) {
- free(*user);
- *user = NULL;
- }
- return rc;
+ if (user)
+ buf = &xuser;
+ } else if (!m && fs) {
+ if (fs)
+ buf = &xfs;
}
+
+ if (buf) {
+ if (ul_buffer_is_empty(buf))
+ ul_buffer_set_chunksize(buf, chunsz);
+ rc = __buffer_append_option(buf, name, namesz, val, valsz);
+ }
+ if (rc)
+ break;
}
- return 0;
+ if (vfs)
+ *vfs = rc ? NULL : ul_buffer_get_data(&xvfs);
+ if (fs)
+ *fs = rc ? NULL : ul_buffer_get_data(&xfs);
+ if (user)
+ *user = rc ? NULL : ul_buffer_get_data(&xuser);
+ if (rc) {
+ ul_buffer_free_data(&xvfs);
+ ul_buffer_free_data(&xfs);
+ ul_buffer_free_data(&xuser);
+ }
+
+ return rc;
}
/**
const struct libmnt_optmap *map, int ignore)
{
struct libmnt_optmap const *maps[1];
+ struct ul_buffer buf = UL_INIT_BUFFER;
char *name, *val, *str = (char *) optstr;
size_t namesz, valsz;
+ int rc = 0;
if (!optstr || !subset)
return -EINVAL;
maps[0] = map;
- *subset = NULL;
- while(!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
- int rc = 0;
+ ul_buffer_set_chunksize(&buf, strlen(optstr)/2);
+
+ while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
const struct libmnt_optmap *ent;
mnt_optmap_get_entry(maps, 1, name, namesz, &ent);
if (valsz && mnt_optmap_entry_novalue(ent))
continue;
- rc = __mnt_optstr_append_option(subset, name, namesz, val, valsz);
- if (rc) {
- free(*subset);
- return rc;
- }
+ rc = __buffer_append_option(&buf, name, namesz, val, valsz);
+ if (rc)
+ break;
}
- return 0;
+ *subset = rc ? NULL : ul_buffer_get_data(&buf);
+ if (rc)
+ ul_buffer_free_data(&buf);
+ return rc;
}