summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-08-01 20:30:49 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-08-01 20:30:49 +0000
commitd6f8a76cf234079b6c616c93e214458478c8bd0b (patch)
treed2d0ab164dff993ed88d19bd15defb57ea64be9e
parent35ff782d714fec1f415bffb588df7b7271c1f9c1 (diff)
Cause ALTER OWNER commands to update the object's ACL, replacing references
to the old owner with the new owner. This is not necessarily right, but it's sure a lot more likely to be what the user wants than doing nothing. Christopher Kings-Lynne, some rework by Tom Lane.
-rw-r--r--src/backend/commands/dbcommands.c43
-rw-r--r--src/backend/commands/functioncmds.c43
-rw-r--r--src/backend/commands/schemacmds.c45
-rw-r--r--src/backend/commands/tablecmds.c44
-rw-r--r--src/backend/commands/tablespace.c42
-rw-r--r--src/backend/utils/adt/acl.c117
-rw-r--r--src/include/utils/acl.h4
7 files changed, 293 insertions, 45 deletions
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index bacf5aa31af..1c1907c5e45 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.138 2004/08/01 06:19:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.139 2004/08/01 20:30:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -768,8 +768,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
void
AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
{
- HeapTuple tuple,
- newtuple;
+ HeapTuple tuple;
Relation rel;
ScanKeyData scankey;
SysScanDesc scan;
@@ -788,8 +787,7 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname)));
- newtuple = heap_copytuple(tuple);
- datForm = (Form_pg_database) GETSTRUCT(newtuple);
+ datForm = (Form_pg_database) GETSTRUCT(tuple);
/*
* If the new owner is the same as the existing owner, consider the
@@ -797,6 +795,14 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
*/
if (datForm->datdba != newOwnerSysId)
{
+ Datum repl_val[Natts_pg_database];
+ char repl_null[Natts_pg_database];
+ char repl_repl[Natts_pg_database];
+ Acl *newAcl;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple newtuple;
+
/* changing owner's database for someone else: must be superuser */
/* note that the someone else need not have any permissions */
if (!superuser())
@@ -804,10 +810,33 @@ AlterDatabaseOwner(const char *dbname, AclId newOwnerSysId)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change owner")));
- /* change owner */
- datForm->datdba = newOwnerSysId;
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
+
+ repl_repl[Anum_pg_database_datdba - 1] = 'r';
+ repl_val[Anum_pg_database_datdba - 1] = Int32GetDatum(newOwnerSysId);
+
+ /*
+ * Determine the modified ACL for the new owner. This is only
+ * necessary when the ACL is non-null.
+ */
+ aclDatum = heap_getattr(tuple,
+ Anum_pg_database_datacl,
+ RelationGetDescr(rel),
+ &isNull);
+ if (!isNull)
+ {
+ newAcl = aclnewowner(DatumGetAclP(aclDatum),
+ datForm->datdba, newOwnerSysId);
+ repl_repl[Anum_pg_database_datacl - 1] = 'r';
+ repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl);
+ }
+
+ newtuple = heap_modifytuple(tuple, rel, repl_val, repl_null, repl_repl);
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
+
+ heap_freetuple(newtuple);
}
systable_endscan(scan);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 20ee9fa3445..58d767d4f76 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.49 2004/06/25 21:55:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.50 2004/08/01 20:30:48 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@@ -738,7 +738,7 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
procOid = LookupFuncNameTypeNames(name, argtypes, false);
- tup = SearchSysCacheCopy(PROCOID,
+ tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
@@ -758,22 +758,51 @@ AlterFunctionOwner(List *name, List *argtypes, AclId newOwnerSysId)
*/
if (procForm->proowner != newOwnerSysId)
{
+ Datum repl_val[Natts_pg_proc];
+ char repl_null[Natts_pg_proc];
+ char repl_repl[Natts_pg_proc];
+ Acl *newAcl;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple newtuple;
+
/* Otherwise, must be superuser to change object ownership */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change owner")));
- /* Modify the owner --- okay to scribble on tup because it's a copy */
- procForm->proowner = newOwnerSysId;
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
+
+ repl_repl[Anum_pg_proc_proowner - 1] = 'r';
+ repl_val[Anum_pg_proc_proowner - 1] = Int32GetDatum(newOwnerSysId);
+
+ /*
+ * Determine the modified ACL for the new owner. This is only
+ * necessary when the ACL is non-null.
+ */
+ aclDatum = SysCacheGetAttr(PROCOID, tup,
+ Anum_pg_proc_proacl,
+ &isNull);
+ if (!isNull)
+ {
+ newAcl = aclnewowner(DatumGetAclP(aclDatum),
+ procForm->proowner, newOwnerSysId);
+ repl_repl[Anum_pg_proc_proacl - 1] = 'r';
+ repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
+ }
+
+ newtuple = heap_modifytuple(tup, rel, repl_val, repl_null, repl_repl);
- simple_heap_update(rel, &tup->t_self, tup);
+ simple_heap_update(rel, &newtuple->t_self, newtuple);
+ CatalogUpdateIndexes(rel, newtuple);
- CatalogUpdateIndexes(rel, tup);
+ heap_freetuple(newtuple);
}
+ ReleaseSysCache(tup);
heap_close(rel, NoLock);
- heap_freetuple(tup);
}
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 35e18c9bfbd..2dead1e15a1 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.20 2004/06/25 21:55:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.21 2004/08/01 20:30:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -320,7 +320,7 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId)
rel = heap_openr(NamespaceRelationName, RowExclusiveLock);
- tup = SearchSysCacheCopy(NAMESPACENAME,
+ tup = SearchSysCache(NAMESPACENAME,
CStringGetDatum(name),
0, 0, 0);
if (!HeapTupleIsValid(tup))
@@ -335,20 +335,49 @@ AlterSchemaOwner(const char *name, AclId newOwnerSysId)
*/
if (nspForm->nspowner != newOwnerSysId)
{
+ Datum repl_val[Natts_pg_namespace];
+ char repl_null[Natts_pg_namespace];
+ char repl_repl[Natts_pg_namespace];
+ Acl *newAcl;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple newtuple;
+
/* Otherwise, must be superuser to change object ownership */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change owner")));
- /* Modify the owner --- okay to scribble on tup because it's a copy */
- nspForm->nspowner = newOwnerSysId;
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
- simple_heap_update(rel, &tup->t_self, tup);
+ repl_repl[Anum_pg_namespace_nspowner - 1] = 'r';
+ repl_val[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(newOwnerSysId);
- CatalogUpdateIndexes(rel, tup);
- }
+ /*
+ * Determine the modified ACL for the new owner. This is only
+ * necessary when the ACL is non-null.
+ */
+ aclDatum = SysCacheGetAttr(NAMESPACENAME, tup,
+ Anum_pg_namespace_nspacl,
+ &isNull);
+ if (!isNull)
+ {
+ newAcl = aclnewowner(DatumGetAclP(aclDatum),
+ nspForm->nspowner, newOwnerSysId);
+ repl_repl[Anum_pg_namespace_nspacl - 1] = 'r';
+ repl_val[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(newAcl);
+ }
+
+ newtuple = heap_modifytuple(tup, rel, repl_val, repl_null, repl_repl);
+
+ simple_heap_update(rel, &newtuple->t_self, newtuple);
+ CatalogUpdateIndexes(rel, newtuple);
+ heap_freetuple(newtuple);
+ }
+
+ ReleaseSysCache(tup);
heap_close(rel, NoLock);
- heap_freetuple(tup);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e78db91e77a..b69e386990e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.122 2004/07/21 22:31:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.123 2004/08/01 20:30:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -5115,7 +5115,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
/* Get its pg_class tuple, too */
class_rel = heap_openr(RelationRelationName, RowExclusiveLock);
- tuple = SearchSysCacheCopy(RELOID,
+ tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relationOid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
@@ -5145,21 +5145,47 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
*/
if (tuple_class->relowner != newOwnerSysId)
{
+ Datum repl_val[Natts_pg_class];
+ char repl_null[Natts_pg_class];
+ char repl_repl[Natts_pg_class];
+ Acl *newAcl;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple newtuple;
+
/* Otherwise, check that we are the superuser */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change owner")));
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
+
+ repl_repl[Anum_pg_class_relowner - 1] = 'r';
+ repl_val[Anum_pg_class_relowner - 1] = Int32GetDatum(newOwnerSysId);
+
/*
- * Okay, this is a valid tuple: change its ownership and write to the
- * heap.
+ * Determine the modified ACL for the new owner. This is only
+ * necessary when the ACL is non-null.
*/
- tuple_class->relowner = newOwnerSysId;
- simple_heap_update(class_rel, &tuple->t_self, tuple);
+ aclDatum = SysCacheGetAttr(RELOID, tuple,
+ Anum_pg_class_relacl,
+ &isNull);
+ if (!isNull)
+ {
+ newAcl = aclnewowner(DatumGetAclP(aclDatum),
+ tuple_class->relowner, newOwnerSysId);
+ repl_repl[Anum_pg_class_relacl - 1] = 'r';
+ repl_val[Anum_pg_class_relacl - 1] = PointerGetDatum(newAcl);
+ }
- /* Keep the catalog indexes up to date */
- CatalogUpdateIndexes(class_rel, tuple);
+ newtuple = heap_modifytuple(tuple, class_rel, repl_val, repl_null, repl_repl);
+
+ simple_heap_update(class_rel, &newtuple->t_self, newtuple);
+ CatalogUpdateIndexes(class_rel, newtuple);
+
+ heap_freetuple(newtuple);
/*
* If we are operating on a table, also change the ownership of any
@@ -5190,7 +5216,7 @@ ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId)
}
}
- heap_freetuple(tuple);
+ ReleaseSysCache(tuple);
heap_close(class_rel, RowExclusiveLock);
relation_close(target_rel, NoLock);
}
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index a08c12305a7..1a9e69dc123 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -45,7 +45,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.6 2004/07/11 19:52:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.7 2004/08/01 20:30:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -757,7 +757,6 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
HeapScanDesc scandesc;
Form_pg_tablespace spcForm;
HeapTuple tup;
- HeapTuple newtuple;
/* Search pg_tablespace */
rel = heap_openr(TableSpaceRelationName, RowExclusiveLock);
@@ -773,8 +772,7 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist", name)));
- newtuple = heap_copytuple(tup);
- spcForm = (Form_pg_tablespace) GETSTRUCT(newtuple);
+ spcForm = (Form_pg_tablespace) GETSTRUCT(tup);
/*
* If the new owner is the same as the existing owner, consider the
@@ -782,16 +780,48 @@ AlterTableSpaceOwner(const char *name, AclId newOwnerSysId)
*/
if (spcForm->spcowner != newOwnerSysId)
{
+ Datum repl_val[Natts_pg_tablespace];
+ char repl_null[Natts_pg_tablespace];
+ char repl_repl[Natts_pg_tablespace];
+ Acl *newAcl;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple newtuple;
+
/* Otherwise, must be superuser to change object ownership */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change owner")));
- /* Modify the owner */
- spcForm->spcowner = newOwnerSysId;
+ memset(repl_null, ' ', sizeof(repl_null));
+ memset(repl_repl, ' ', sizeof(repl_repl));
+
+ repl_repl[Anum_pg_tablespace_spcowner - 1] = 'r';
+ repl_val[Anum_pg_tablespace_spcowner - 1] = Int32GetDatum(newOwnerSysId);
+
+ /*
+ * Determine the modified ACL for the new owner. This is only
+ * necessary when the ACL is non-null.
+ */
+ aclDatum = heap_getattr(tup,
+ Anum_pg_tablespace_spcacl,
+ RelationGetDescr(rel),
+ &isNull);
+ if (!isNull)
+ {
+ newAcl = aclnewowner(DatumGetAclP(aclDatum),
+ spcForm->spcowner, newOwnerSysId);
+ repl_repl[Anum_pg_tablespace_spcacl - 1] = 'r';
+ repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
+ }
+
+ newtuple = heap_modifytuple(tup, rel, repl_val, repl_null, repl_repl);
+
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
+
+ heap_freetuple(newtuple);
}
heap_endscan(scandesc);
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;
}
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index f7779be589d..cf13038ad00 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.71 2004/06/18 06:14:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.72 2004/08/01 20:30:49 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@@ -224,6 +224,8 @@ typedef enum AclObjectKind
extern Acl *acldefault(GrantObjectType objtype, AclId ownerid);
extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,
int modechg, AclId ownerid, DropBehavior behavior);
+extern Acl *aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid);
+
extern AclMode aclmask(const Acl *acl, AclId userid, AclId ownerid,
AclMode mask, AclMaskHow how);