]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Cause ALTER OWNER commands to update the object's ACL, replacing references
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Aug 2004 20:30:49 +0000 (20:30 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Aug 2004 20:30:49 +0000 (20:30 +0000)
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.

src/backend/commands/dbcommands.c
src/backend/commands/functioncmds.c
src/backend/commands/schemacmds.c
src/backend/commands/tablecmds.c
src/backend/commands/tablespace.c
src/backend/utils/adt/acl.c
src/include/utils/acl.h

index bacf5aa31af92ddf979313b30556523575e7c05b..1c1907c5e453d5c3bf2903430fb30d31c9ba6814 100644 (file)
@@ -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);
index 20ee9fa3445bd01f86fd8e78a9ab445837431df6..58d767d4f76ea2b7a756813edb113d6ba7b1df71 100644 (file)
@@ -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);
 }
 
 
index 35e18c9bfbd3df7739ca81c3fa7d7b4a014a9e65..2dead1e15a123b4a7390266789049b49cfa54ed3 100644 (file)
@@ -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);
 }
index e78db91e77af06d9a3a15cf169da0afe25cd0ba2..b69e386990ee1f021d951c1ee13abb03e13550fe 100644 (file)
@@ -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);
 }
index a08c12305a76f5afb692e49af1c1e598e35c06e2..1a9e69dc12398cd4d7ad7acd4fd9610a23a1dc12 100644 (file)
@@ -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);
index 4b45ca7c4d479f2345af028de5758b3958e9439a..290c3ed49d2d04335e0531b9706af0af0bda2ca7 100644 (file)
@@ -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;
 }
index f7779be589d37b0cd78e9c0a3c0abdf77d98fbf7..cf13038ad004be74ee9f117ba2a6f5b768580b4e 100644 (file)
@@ -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);