summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1996-01-01 22:54:47 +0000
committerMiles Bader <miles@gnu.org>1996-01-01 22:54:47 +0000
commit12135a5bdf9e99418dfc08766f1697b34f89660d (patch)
tree90812a4b69cb504b7ac4dbe871d161b226bcd34f
parenta3127e234a63121775f2113df40d49e31ac3b5ff (diff)
(idvec_free_wrapper, idvec_free, idvec_ensure, idvec_grow,
idvec_tail_contains, idvec_add_new, idvec_insert_new, idvec_merge_ids, idvec_setid): New functions. (idvec_insert): Rewritten to use idvec_grow().
-rw-r--r--libshouldbeinlibc/idvec.c178
1 files changed, 152 insertions, 26 deletions
diff --git a/libshouldbeinlibc/idvec.c b/libshouldbeinlibc/idvec.c
index d8424fdd..01eabdd6 100644
--- a/libshouldbeinlibc/idvec.c
+++ b/libshouldbeinlibc/idvec.c
@@ -22,60 +22,186 @@
#include <string.h>
#include <idvec.h>
-/* Return a new idvec, or NULL if there wasn't enough memory. */
+typedef uid_t id_t;
+
+/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
struct idvec *
make_idvec ()
{
struct idvec *idvec = malloc (sizeof (struct idvec));
if (idvec)
{
+ idvec->alloced = idvec->num = 0;
idvec->ids = 0;
- idvec->num = idvec->alloced = 0;
}
return idvec;
}
-/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
- enough memory, or 0. */
+/* Free's IDVEC, but not the storage pointed to by the IDS field. */
+void
+idvec_free_wrapper (struct idvec *idvec)
+{
+ free (idvec);
+}
+
+void
+idvec_free (struct idvec *idvec)
+{
+ if (idvec->alloced)
+ free (idvec->ids);
+ free (idvec);
+}
+
+/* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus
+ ensuring that any subsequent ids added won't return a memory allocation
+ error unless it would result in more ids that NUM. ENOMEM is returned if
+ a memory allocation error occurs. */
error_t
-idvec_insert (struct idvec *idvec, unsigned pos, uid_t id)
+idvec_ensure (struct idvec *idvec, unsigned num)
{
- if (idvec->alloced == idvec->num)
+ if (num > idvec->alloced)
{
- unsigned new_size = idvec->alloced * 2 + 1;
- int *new_ids = realloc (idvec->ids, new_size * sizeof (int));
-
- if (! new_ids)
+ id_t *_ids = realloc (idvec->ids, num);
+ if (! _ids)
return ENOMEM;
-
- idvec->alloced = new_size;
- idvec->ids = new_ids;
+ idvec->ids = _ids;
+ idvec->alloced = num;
}
+ return 0;
+}
+
+/* Like idvec_ensure(), but takes INC, the increment of the number of ids
+ already in IDVEC as an argument. */
+error_t
+idvec_grow (struct idvec *idvec, unsigned inc)
+{
+ return idvec_ensure (idvec, idvec->num + inc);
+}
+
+/* Returns true if IDVEC contains ID, at or after position POS. */
+int
+idvec_tail_contains (struct idvec *idvec, unsigned pos, id_t id)
+{
+ while (pos < idvec->num)
+ if (idvec->ids[pos++] == id)
+ return 1;
+ return 0;
+}
+
+/* Returns true if IDVEC contains ID. */
+int
+idvec_contains (struct idvec *idvec, id_t id)
+{
+ return idvec_tail_contains (idvec, 0, id);
+}
+
+/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
+ enough memory, or 0. */
+error_t
+idvec_insert (struct idvec *idvec, unsigned pos, id_t id)
+{
+ error_t err = 0;
+ unsigned num = idvec->num;
- if (pos < idvec->num)
- bcopy (idvec->ids + pos, idvec->ids + pos + 1, idvec->num - pos);
+ if (idvec->alloced == num)
+ /* If we seem to be growing by just one, actually prealloc some more. */
+ err = idvec_grow (idvec, num + 1);
+ else
+ err = idvec_grow (idvec, 1);
- idvec->ids[pos] = id;
- idvec->num++;
+ if (! err)
+ {
+ id_t *ids = idvec->ids;
+ if (pos < num)
+ bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (id_t));
+ else if (pos > num)
+ bzero (ids + num, (pos - num) * sizeof (id_t));
+ ids[pos] = id;
+ idvec->num = num + 1;
+ }
- return 0;
+ return err;
}
/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
or 0. */
error_t
-idvec_add (struct idvec *idvec, uid_t id)
+idvec_add (struct idvec *idvec, id_t id)
{
return idvec_insert (idvec, idvec->num, id);
}
+
+/* IF IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
+ there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_add_new (struct idvec *idvec, id_t id)
+{
+ if (idvec_contains (idvec, id))
+ return 0;
+ else
+ return idvec_add (idvec, id);
+}
-/* Returns true if IDVEC contains ID. */
-int
-idvec_contains (struct idvec *idvec, uid_t id)
+/* IF IDVEC doesn't contain ID at position POS or after, insert it at POS,
+ returning ENOMEM if there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_insert_new (struct idvec *idvec, unsigned pos, id_t id)
+{
+ if (idvec_tail_contains (idvec, pos, id))
+ return 0;
+ else
+ return idvec_insert (idvec, pos, id);
+}
+
+/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as if with
+ idvec_add_new(). */
+error_t
+idvec_merge_ids (struct idvec *idvec, id_t *ids, unsigned num)
+{
+ error_t err = 0;
+ while (num-- > 0 && !err)
+ err = idvec_add_new (idvec, *ids++);
+ return err;
+}
+
+/* EFF and AVAIL should be idvec's corresponding to a processes effective and
+ available ids. ID replaces the first id in EFF, and what it replaces is
+ preserved by adding it to AVAIL (if not already present). If SECURE is
+ non-NULL, and ID was not previously present in either EFF or AVAIL, then
+ *SECURE is set to true. ENOMEM is returned if a malloc fails, otherwise
+ 0. The return parameters are only touched if this call succeeds. */
+error_t
+idvec_setid (struct idvec *eff, struct idvec *avail, id_t id, int *secure)
{
- unsigned i;
- for (i = 0; i < idvec->num; i++)
- if (idvec->ids[i] == id)
- return 1;
+ error_t err;
+ /* True if ID was not previously present in either EFF or AVAIL. */
+ int _secure = !idvec_contains (eff, id) && !idvec_contains (avail, id);
+
+ if (eff->num > 0)
+ /* If there are any old effective ids, we replace eff[0] with ID, and try
+ to preserve the old eff[0] by putting it in AVAIL list if necessary. */
+ {
+ if (avail->num == 0)
+ /* The old eff[0] becomes avail[0] (the posix real id). */
+ err = idvec_add (avail, eff->ids[0]);
+ else
+ /* We preserve the old real id, and add eff[0] to the list of saved
+ ids (if necessary). Inserting it means that the latest id saved
+ will correspond to the (single) posix saved id. */
+ err = idvec_insert_new (avail, 1, eff->ids[0]);
+
+ /* Replace eff[0] with the new id. */
+ eff->ids[0] = id;
+ }
+ else
+ /* No previous effective ids, just make ID the first one. */
+ err = idvec_add (eff, id);
+
+ if (err)
+ return err;
+
+ if (_secure && secure && !*secure)
+ *secure = 1;
+
return 0;
}