aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2016-03-02 17:45:05 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2016-03-02 17:47:58 +0100
commita84eaa56d0d2edd0872d1d881b82411dc06c6c92 (patch)
tree3726af3cd9dca6b34ae72a45a7e1d21219c3e4cb
parent740c64f92c24da30a8636b836a21e91fcba70463 (diff)
afm-db: commenting, bug fixing, improving
Change-Id: I208e8eb72c42231e077276fa61dd4ad5e952b2c4 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/afm-db.c454
1 files changed, 280 insertions, 174 deletions
diff --git a/src/afm-db.c b/src/afm-db.c
index b9cf1e0..257e70f 100644
--- a/src/afm-db.c
+++ b/src/afm-db.c
@@ -31,159 +31,90 @@
#include "wgt-info.h"
#include "afm-db.h"
-struct afapps {
- struct json_object *pubarr;
- struct json_object *direct;
- struct json_object *byapp;
+/*
+ * The structure afm_apps records the data about applications
+ * for several accesses.
+ */
+struct afm_apps {
+ struct json_object *pubarr; /* array of the public data of applications */
+ struct json_object *direct; /* hash of applications by their id */
+ struct json_object *byapp; /* hash of versions of applications by their appid */
};
+/*
+ * Two types of directory are handled:
+ * - root directories: contains subdirectories appid/versio containing the applications
+ * - application directories: it contains an application
+ */
enum dir_type {
- type_root,
- type_app
+ type_root, /* type for root directory */
+ type_app /* type for application directory */
};
+/*
+ * Structure for recording a path to application(s)
+ * in the list of directories.
+ */
struct afm_db_dir {
- struct afm_db_dir *next;
- char *path;
- enum dir_type type;
+ struct afm_db_dir *next; /* link to the next item of the list */
+ enum dir_type type; /* the type of the path */
+ char path[1]; /* the path of the directory */
};
+/*
+ * The structure afm_db records the applications
+ * for a set of directories recorded as a linked list
+ */
struct afm_db {
- int refcount;
- struct afm_db_dir *dirhead;
- struct afm_db_dir *dirtail;
- struct afapps applications;
+ int refcount; /* count of references to the structure */
+ struct afm_db_dir *dirhead; /* first directory of the set of directories */
+ struct afm_db_dir *dirtail; /* last directory of the set of directories */
+ struct afm_apps applications; /* the data about applications */
};
-struct afm_db *afm_db_create()
-{
- struct afm_db *afdb = malloc(sizeof * afdb);
- if (afdb == NULL)
- errno = ENOMEM;
- else {
- afdb->refcount = 1;
- afdb->dirhead = NULL;
- afdb->dirtail = NULL;
- afdb->applications.pubarr = NULL;
- afdb->applications.direct = NULL;
- afdb->applications.byapp = NULL;
- }
- return afdb;
-}
-
-void afm_db_addref(struct afm_db *afdb)
-{
- assert(afdb);
- afdb->refcount++;
-}
-
-void afm_db_unref(struct afm_db *afdb)
-{
- struct afm_db_dir *dir;
- assert(afdb);
- if (!--afdb->refcount) {
- json_object_put(afdb->applications.pubarr);
- json_object_put(afdb->applications.direct);
- json_object_put(afdb->applications.byapp);
- while (afdb->dirhead != NULL) {
- dir = afdb->dirhead;
- afdb->dirhead = dir->next;
- free(dir->path);
- free(dir);
- }
- free(afdb);
- }
-}
-
-int add_dir(struct afm_db *afdb, const char *path, enum dir_type type)
-{
- struct afm_db_dir *dir;
- char *r;
-
- assert(afdb);
-
- /* don't depend on the cwd and unique name */
- r = realpath(path, NULL);
- if (!r)
- return -1;
-
- /* avoiding duplications */
- dir = afdb->dirhead;
- while(dir != NULL && (strcmp(dir->path, path) || dir->type != type))
- dir = dir ->next;
- if (dir != NULL) {
- free(r);
- return 0;
- }
-
- /* allocates the structure */
- dir = malloc(sizeof * dir);
- if (dir == NULL) {
- free(r);
- errno = ENOMEM;
- return -1;
- }
-
- /* add */
- dir->next = NULL;
- dir->path = r;
- dir->type = type;
- if (afdb->dirtail == NULL)
- afdb->dirhead = dir;
- else
- afdb->dirtail->next = dir;
- afdb->dirtail = dir;
- return 0;
-}
-
-int afm_db_add_root(struct afm_db *afdb, const char *path)
-{
- return add_dir(afdb, path, type_root);
-}
+/*
+ * The structure enumdata records data used when enumerating
+ * application directories of a root directory.
+ */
+struct enumdata {
+ char path[PATH_MAX]; /* "current" computed path */
+ int length; /* length of path */
+ struct afm_apps apps; /* */
+};
-int afm_db_add_application(struct afm_db *afdb, const char *path)
+/*
+ * Release the data of the afm_apps object 'apps'.
+ */
+static void apps_put(struct afm_apps *apps)
{
- return add_dir(afdb, path, type_app);
+ json_object_put(apps->pubarr);
+ json_object_put(apps->direct);
+ json_object_put(apps->byapp);
}
-static int addapp(struct afapps *apps, const char *path)
+/*
+ * Adds the application widget 'desc' of the directory 'path' to the
+ * afm_apps object 'apps'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ */
+static int addwgt(struct afm_apps *apps, const char *path, const struct wgt_desc *desc)
{
- struct wgt_info *info;
- const struct wgt_desc *desc;
const struct wgt_desc_feature *feat;
- struct json_object *priv = NULL, *pub, *bya, *plugs, *str;
-
- /* connect to the widget */
- info = wgt_info_createat(AT_FDCWD, path, 0, 1, 0);
- if (info == NULL) {
- if (errno == ENOENT)
- return 0; /* silently ignore bad directories */
- goto error;
- }
- desc = wgt_info_desc(info);
+ struct json_object *priv, *pub, *bya, *plugs, *str;
/* create the application structure */
priv = json_object_new_object();
if (!priv)
- goto error2;
-
- pub = json_object_new_object();
- if (!priv)
- goto error2;
-
- if (!j_add(priv, "public", pub)) {
- json_object_put(pub);
- goto error2;
- }
+ return -1;
- plugs = json_object_new_array();
- if (!priv)
- goto error2;
+ pub = j_add_new_object(priv, "public");
+ if (!pub)
+ goto error;
- if (!j_add(priv, "plugins", plugs)) {
- json_object_put(plugs);
- goto error2;
- }
+ plugs = j_add_new_array(priv, "plugins");
+ if (!plugs)
+ goto error;
if(!j_add_string(priv, "id", desc->id)
|| !j_add_string(priv, "path", path)
@@ -197,68 +128,83 @@ static int addapp(struct afapps *apps, const char *path)
|| !j_add_string(pub, "description", desc->description)
|| !j_add_string(pub, "shortname", desc->name_short)
|| !j_add_string(pub, "author", desc->author))
- goto error2;
+ goto error;
+ /* extract plugins from features */
feat = desc->features;
while (feat) {
static const char prefix[] = FWK_PREFIX_PLUGIN;
if (!memcmp(feat->name, prefix, sizeof prefix - 1)) {
str = json_object_new_string (feat->name + sizeof prefix - 1);
if (str == NULL)
- goto error2;
+ goto error;
if (json_object_array_add(plugs, str)) {
json_object_put(str);
- goto error2;
+ goto error;
}
}
feat = feat->next;
}
/* record the application structure */
+ if (!j_add(apps->direct, desc->idaver, priv))
+ goto error;
+
+ if (json_object_array_add(apps->pubarr, pub))
+ goto error;
+ json_object_get(pub);
+
if (!json_object_object_get_ex(apps->byapp, desc->id, &bya)) {
- bya = json_object_new_object();
+ bya = j_add_new_object(apps->byapp, desc->id);
if (!bya)
- goto error2;
- if (!j_add(apps->byapp, desc->id, bya)) {
- json_object_put(bya);
- goto error2;
- }
+ goto error;
}
- if (!j_add(apps->direct, desc->idaver, priv))
- goto error2;
+ if (!j_add(bya, desc->version, priv))
+ goto error;
json_object_get(priv);
-
- if (!j_add(bya, desc->version, priv)) {
- json_object_put(priv);
- goto error2;
- }
-
- if (json_object_array_add(apps->pubarr, pub))
- goto error2;
-
- wgt_info_unref(info);
return 0;
-error2:
- json_object_put(priv);
- wgt_info_unref(info);
error:
+ json_object_put(priv);
return -1;
}
-struct enumdata {
- char path[PATH_MAX];
- int length;
- struct afapps apps;
-};
+/*
+ * Adds the application widget in the directory 'path' to the
+ * afm_apps object 'apps'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ */
+static int addapp(struct afm_apps *apps, const char *path)
+{
+ int rc;
+ struct wgt_info *info;
+ /* connect to the widget */
+ info = wgt_info_createat(AT_FDCWD, path, 0, 1, 0);
+ if (info == NULL) {
+ if (errno == ENOENT)
+ return 0; /* silently ignore bad directories */
+ return -1;
+ }
+ /* adds the widget */
+ rc = addwgt(apps, path, wgt_info_desc(info));
+ wgt_info_unref(info);
+ return rc;
+}
+
+/*
+ * Enumerate the directories designated by 'data' and call the
+ * function 'callto' for each of them.
+ */
static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
{
DIR *dir;
int rc;
- char *beg, *end;
+ char *beg;
struct dirent entry, *e;
+ size_t len;
/* opens the directory */
dir = opendir(data->path);
@@ -274,8 +220,12 @@ static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
while (!rc && e) {
if (entry.d_name[0] != '.' || (entry.d_name[1] && (entry.d_name[1] != '.' || entry.d_name[2]))) {
/* prepare callto */
- end = stpcpy(beg, entry.d_name);
- data->length = end - data->path;
+ len = strlen(entry.d_name);
+ if (beg + len >= data->path + sizeof data->path) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ data->length = stpcpy(beg, entry.d_name) - data->path;
/* call the function */
rc = callto(data);
if (rc)
@@ -287,24 +237,156 @@ static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
return rc;
}
+/*
+ * called for each version directory.
+ */
static int recordapp(struct enumdata *data)
{
return addapp(&data->apps, data->path);
}
-/* enumerate the versions */
+/*
+ * called for each application directory.
+ * enumerate directories of the existing versions.
+ */
static int enumvers(struct enumdata *data)
{
int rc = enumentries(data, recordapp);
return !rc || errno != ENOTDIR ? 0 : rc;
}
-/* regenerate the list of applications */
+/*
+ * Adds the directory of 'path' and 'type' to the afm_db object 'afdb'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ * Possible errno values: ENOMEM, ENAMETOOLONG
+ */
+static int add_dir(struct afm_db *afdb, const char *path, enum dir_type type)
+{
+ struct afm_db_dir *dir;
+ size_t len;
+
+ assert(afdb);
+
+ /* check size */
+ len = strlen(path);
+ if (len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* avoiding duplications */
+ dir = afdb->dirhead;
+ while(dir != NULL && (strcmp(dir->path, path) || dir->type != type))
+ dir = dir ->next;
+ if (dir != NULL)
+ return 0;
+
+ /* allocates the structure */
+ dir = malloc(strlen(path) + sizeof * dir);
+ if (dir == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* add it at tail */
+ dir->next = NULL;
+ dir->type = type;
+ strcpy(dir->path, path);
+ if (afdb->dirtail == NULL)
+ afdb->dirhead = dir;
+ else
+ afdb->dirtail->next = dir;
+ afdb->dirtail = dir;
+ return 0;
+}
+
+/*
+ * Creates an afm_db object and returns it with one reference added.
+ * Return NULL with errno = ENOMEM if memory exhausted.
+ */
+struct afm_db *afm_db_create()
+{
+ struct afm_db *afdb = malloc(sizeof * afdb);
+ if (afdb == NULL)
+ errno = ENOMEM;
+ else {
+ afdb->refcount = 1;
+ afdb->dirhead = NULL;
+ afdb->dirtail = NULL;
+ afdb->applications.pubarr = NULL;
+ afdb->applications.direct = NULL;
+ afdb->applications.byapp = NULL;
+ }
+ return afdb;
+}
+
+/*
+ * Adds a reference to an existing afm_db.
+ */
+void afm_db_addref(struct afm_db *afdb)
+{
+ assert(afdb);
+ afdb->refcount++;
+}
+
+/*
+ * Removes a reference to an existing afm_db object.
+ * Removes the objet if there no more reference to it.
+ */
+void afm_db_unref(struct afm_db *afdb)
+{
+ struct afm_db_dir *dir;
+
+ assert(afdb);
+ if (!--afdb->refcount) {
+ /* no more reference, clean the memory used by the object */
+ apps_put(&afdb->applications);
+ while (afdb->dirhead != NULL) {
+ dir = afdb->dirhead;
+ afdb->dirhead = dir->next;
+ free(dir);
+ }
+ free(afdb);
+ }
+}
+
+/*
+ * Adds the root directory of 'path' to the afm_db object 'afdb'.
+ * Be aware that no check is done on the directory of 'path' that will
+ * only be used within calls to the function 'afm_db_update_applications'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ * Possible errno values: ENOMEM, ENAMETOOLONG
+ */
+int afm_db_add_root(struct afm_db *afdb, const char *path)
+{
+ return add_dir(afdb, path, type_root);
+}
+
+/*
+ * Adds the application directory of 'path' to the afm_db object 'afdb'.
+ * Be aware that no check is done on the directory of 'path' that will
+ * only be used within calls to the function 'afm_db_update_applications'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ * Possible errno values: ENOMEM, ENAMETOOLONG
+ */
+int afm_db_add_application(struct afm_db *afdb, const char *path)
+{
+ return add_dir(afdb, path, type_app);
+}
+
+/*
+ * Regenerate the list of applications of the afm_bd object 'afdb'.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ */
int afm_db_update_applications(struct afm_db *afdb)
{
int rc;
struct enumdata edata;
- struct afapps oldapps;
+ struct afm_apps oldapps;
struct afm_db_dir *dir;
/* create the result */
@@ -315,7 +397,7 @@ int afm_db_update_applications(struct afm_db *afdb)
errno = ENOMEM;
goto error;
}
- /* for each root */
+ /* for each directory of afdb */
for (dir = afdb->dirhead ; dir != NULL ; dir = dir->next) {
if (dir->type == type_root) {
edata.length = stpcpy(edata.path, dir->path) - edata.path;
@@ -331,28 +413,39 @@ int afm_db_update_applications(struct afm_db *afdb)
/* commit the result */
oldapps = afdb->applications;
afdb->applications = edata.apps;
- json_object_put(oldapps.pubarr);
- json_object_put(oldapps.direct);
- json_object_put(oldapps.byapp);
+ apps_put(&oldapps);
return 0;
error:
- json_object_put(edata.apps.pubarr);
- json_object_put(edata.apps.direct);
- json_object_put(edata.apps.byapp);
+ apps_put(&edata.apps);
return -1;
}
+/*
+ * Ensure that applications of the afm_bd object 'afdb' are listed.
+ * Returns 0 in case of success.
+ * Returns -1 and set errno in case of error
+ */
int afm_db_ensure_applications(struct afm_db *afdb)
{
return afdb->applications.pubarr ? 0 : afm_db_update_applications(afdb);
}
+/*
+ * Get the list of the applications public data of the afm_db object 'afdb'.
+ * The list is returned as a JSON-array that must be released using 'json_object_put'.
+ * Returns NULL in case of error.
+ */
struct json_object *afm_db_application_list(struct afm_db *afdb)
{
return afm_db_ensure_applications(afdb) ? NULL : json_object_get(afdb->applications.pubarr);
}
+/*
+ * Get the private data of the applications of 'id' in the afm_db object 'afdb'.
+ * It returns a JSON-object that must be released using 'json_object_put'.
+ * Returns NULL in case of error.
+ */
struct json_object *afm_db_get_application(struct afm_db *afdb, const char *id)
{
struct json_object *result;
@@ -361,10 +454,23 @@ struct json_object *afm_db_get_application(struct afm_db *afdb, const char *id)
return NULL;
}
+/*
+ * Get the public data of the applications of 'id' in the afm_db object 'afdb'.
+ * It returns a JSON-object that must be released using 'json_object_put'.
+ * Returns NULL in case of error.
+ */
struct json_object *afm_db_get_application_public(struct afm_db *afdb, const char *id)
{
- struct json_object *result = afm_db_get_application(afdb, id);
- return result && json_object_object_get_ex(result, "public", &result) ? json_object_get(result) : NULL;
+ struct json_object *result;
+ struct json_object *priv = afm_db_get_application(afdb, id);
+ if (priv == NULL)
+ return NULL;
+ if (json_object_object_get_ex(priv, "public", &result))
+ json_object_get(result);
+ else
+ result = NULL;
+ json_object_put(priv);
+ return result;
}