diff options
Diffstat (limited to 'src/backend/utils/adt/acl.c')
-rw-r--r-- | src/backend/utils/adt/acl.c | 117 |
1 files changed, 110 insertions, 7 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 4b45ca7c4d4..290c3ed49d2 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.107 2004/07/12 20:23:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.108 2004/08/01 20:30:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -717,6 +717,109 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip, return new_acl; } +/* + * Update an ACL array to reflect a change of owner to the parent object + * + * old_acl: the input ACL array (must not be NULL) + * oldownerid: AclId of the old object owner + * newownerid: AclId of the new object owner + * + * The result is a modified copy; the input object is not changed. + * + * NB: caller is responsible for having detoasted the input ACL, if needed. + */ +Acl * +aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid) +{ + Acl *new_acl; + AclItem *new_aip; + AclItem *old_aip; + AclItem *dst_aip; + AclItem *src_aip; + AclItem *targ_aip; + bool newpresent = false; + int dst, + src, + targ, + num; + + /* + * Make a copy of the given ACL, substituting new owner ID for old + * wherever it appears as either grantor or grantee. Also note if + * the new owner ID is already present. + */ + num = ACL_NUM(old_acl); + old_aip = ACL_DAT(old_acl); + new_acl = allocacl(num); + new_aip = ACL_DAT(new_acl); + memcpy(new_aip, old_aip, num * sizeof(AclItem)); + for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++) + { + /* grantor is always a UID, but grantee might not be */ + if (dst_aip->ai_grantor == oldownerid) + dst_aip->ai_grantor = newownerid; + else if (dst_aip->ai_grantor == newownerid) + newpresent = true; + if (ACLITEM_GET_IDTYPE(*dst_aip) == ACL_IDTYPE_UID) + { + if (dst_aip->ai_grantee == oldownerid) + dst_aip->ai_grantee = newownerid; + else if (dst_aip->ai_grantee == newownerid) + newpresent = true; + } + } + + /* + * If the old ACL contained any references to the new owner, then we + * may now have generated an ACL containing duplicate entries. Find + * them and merge them so that there are not duplicates. (This is + * relatively expensive since we use a stupid O(N^2) algorithm, but + * it's unlikely to be the normal case.) + * + * To simplify deletion of duplicate entries, we temporarily leave them + * in the array but set their privilege masks to zero; when we reach + * such an entry it's just skipped. (Thus, a side effect of this code + * will be to remove privilege-free entries, should there be any in the + * input.) dst is the next output slot, targ is the currently considered + * input slot (always >= dst), and src scans entries to the right of targ + * looking for duplicates. Once an entry has been emitted to dst it is + * known duplicate-free and need not be considered anymore. + */ + if (newpresent) + { + dst = 0; + for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++) + { + /* ignore if deleted in an earlier pass */ + if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS) + continue; + /* find and merge any duplicates */ + for (src = targ + 1, src_aip = targ_aip + 1; src < num; + src++, src_aip++) + { + if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS) + continue; + if (aclitem_match(targ_aip, src_aip)) + { + ACLITEM_SET_RIGHTS(*targ_aip, + ACLITEM_GET_RIGHTS(*targ_aip) | + ACLITEM_GET_RIGHTS(*src_aip)); + /* mark the duplicate deleted */ + ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS); + } + } + /* and emit to output */ + new_aip[dst] = *targ_aip; + dst++; + } + /* Adjust array size to be 'dst' items */ + ARR_DIMS(new_acl)[0] = dst; + ARR_SIZE(new_acl) = ACL_N_SIZE(dst); + } + + return new_acl; +} + /* * When granting grant options, we must disallow attempts to set up circular @@ -2373,15 +2476,15 @@ convert_tablespace_name(text *tablespacename) { char *spcname; Oid oid; - + spcname = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(tablespacename))); + PointerGetDatum(tablespacename))); oid = get_tablespace_oid(spcname); - if (!OidIsValid(oid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("tablespace \"%s\" does not exist", spcname))); + if (!OidIsValid(oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", spcname))); return oid; } |