From 4646c4a3ef6171a0ddec4fcfe0c6aa34b50501cd Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 11:54:10 +0000 Subject: Improve the interface for dircat_make_node * dircat.c, dircat.h (dircat_make_node): Use an explicit array size for DIRS, fail with ENOMEM is any of them is NULL, and release the reference on the non-NULL nodes on any error. * main.c (root_make_node): Use the new interface. --- dircat.c | 37 +++++++++++++++++++++++-------------- dircat.h | 17 +++++++++-------- main.c | 27 ++++++--------------------- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/dircat.c b/dircat.c index bb66508..d043486 100644 --- a/dircat.c +++ b/dircat.c @@ -4,7 +4,8 @@ struct dircat_node { - struct node **dirs; + int num_dirs; + struct node *dirs[0]; }; static error_t @@ -17,7 +18,7 @@ dircat_get_contents (void *hook, char **contents, ssize_t *contents_len) pos = 0; *contents = malloc (sz = 512); - for (i=0; dcn->dirs[i]; i++) + for (i=0; i < dcn->num_dirs; i++) { char *subcon; ssize_t sublen; @@ -49,19 +50,20 @@ dircat_lookup (void *hook, const char *name, struct node **np) int i; err = ENOENT; - for (i=0; err && dcn->dirs[i]; i++) + for (i=0; err && i < dcn->num_dirs; i++) err = procfs_lookup (dcn->dirs[i], name, np); return err; } static void -dircat_release_dirs (struct node **dirs) +dircat_release_dirs (struct node *const *dirs, int num_dirs) { int i; - for (i=0; dirs[i]; i++) - netfs_nrele (dirs[i]); + for (i=0; i < num_dirs; i++) + if (dirs[i]) + netfs_nrele (dirs[i]); } static void @@ -69,12 +71,12 @@ dircat_cleanup (void *hook) { struct dircat_node *dcn = hook; - dircat_release_dirs (dcn->dirs); + dircat_release_dirs (dcn->dirs, dcn->num_dirs); free (dcn); } struct node * -dircat_make_node (struct node **dirs) +dircat_make_node (struct node *const *dirs, int num_dirs) { static struct procfs_node_ops ops = { .get_contents = dircat_get_contents, @@ -85,15 +87,22 @@ dircat_make_node (struct node **dirs) .enable_refresh_hack_and_break_readdir = 1, }; struct dircat_node *dcn; + int i; + + for (i=0; i < num_dirs; i++) + if (! dirs[i]) + goto fail; - dcn = malloc (sizeof *dcn); + dcn = malloc (sizeof *dcn + num_dirs * sizeof dcn->dirs[0]); if (! dcn) - { - dircat_release_dirs (dirs); - return NULL; - } + goto fail; - dcn->dirs = dirs; + dcn->num_dirs = num_dirs; + memcpy (dcn->dirs, dirs, num_dirs * sizeof dcn->dirs[0]); return procfs_make_node (&ops, dcn); + +fail: + dircat_release_dirs (dirs, num_dirs); + return NULL; } diff --git a/dircat.h b/dircat.h index cb22852..951d202 100644 --- a/dircat.h +++ b/dircat.h @@ -1,9 +1,10 @@ -/* Append the contents of multiple directories. DIRS is a - NULL-terminated array of directory nodes. One reference is consumed - for each of them, even on ENOMEM, in which case NULL is returned. - DIRS has to be static data for now, or at list remain available and - unchanged for the duration of the created node's life. Strange - things will happen if they have entries with the same name or if one - of them is not a directory. */ +/* Append the contents of NUM_DIRS directories. DIRS is an array of + directory nodes. One reference is consumed for each of them. If a + memory allocation error occurs, or if one of the directories is a + NULL pointer, the references are dropped immediately and NULL is + returned. The given DIRS array is duplicated and can therefore be + allocated on the caller's stack. Strange things will happen if some + elements of DIRS have entries with the same name or if one of them is + not a directory. */ struct node * -dircat_make_node (struct node **dirs); +dircat_make_node (struct node *const *dirs, int num_dirs); diff --git a/main.c b/main.c index 06c1da0..eaab986 100644 --- a/main.c +++ b/main.c @@ -118,35 +118,20 @@ struct argp argp = { error_t root_make_node (struct ps_context *pc, struct node **np) { - /* We never have two root nodes alive simultaneously, so it's ok to - have this as static data. */ - static struct node *root_dirs[3]; + struct node *root_dirs[] = { + proclist_make_node (pc), + rootdir_make_node (pc), + }; - root_dirs[0] = proclist_make_node (pc); - if (! root_dirs[0]) - goto nomem; - - root_dirs[1] = rootdir_make_node (pc); - if (! root_dirs[1]) - goto nomem; - - root_dirs[2] = NULL; - *np = dircat_make_node (root_dirs); + *np = dircat_make_node (root_dirs, sizeof root_dirs / sizeof root_dirs[0]); if (! *np) - goto nomem; + return ENOMEM; /* Since this one is not created through proc_lookup(), we have to affect an inode number to it. */ (*np)->nn_stat.st_ino = * (uint32_t *) "PROC"; return 0; - -nomem: - if (root_dirs[1]) - netfs_nrele (root_dirs[1]); - if (root_dirs[0]) - netfs_nrele (root_dirs[0]); - return ENOMEM; } int main (int argc, char **argv) -- cgit v1.2.3