diff options
author | Miles Bader <miles@gnu.org> | 1996-01-01 22:54:47 +0000 |
---|---|---|
committer | Miles Bader <miles@gnu.org> | 1996-01-01 22:54:47 +0000 |
commit | 12135a5bdf9e99418dfc08766f1697b34f89660d (patch) | |
tree | 90812a4b69cb504b7ac4dbe871d161b226bcd34f | |
parent | a3127e234a63121775f2113df40d49e31ac3b5ff (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.c | 178 |
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; } |