pts-supergroups-20030114
authorKevin Coffman <kwc@citi.umich.edu>
Wed, 15 Jan 2003 17:36:07 +0000 (17:36 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 15 Jan 2003 17:36:07 +0000 (17:36 +0000)
thanks to nneul@umr.edu
add configure switch and support code for groups in groups

17 files changed:
acinclude.m4
src/ptserver/Makefile.in
src/ptserver/db_verify.c
src/ptserver/display.c
src/ptserver/map.c [new file with mode: 0644]
src/ptserver/map.h [new file with mode: 0644]
src/ptserver/ptclient.c
src/ptserver/ptclient.h
src/ptserver/ptint.xg
src/ptserver/ptopcodes.h
src/ptserver/ptprocs.c
src/ptserver/pts.c
src/ptserver/ptserver.c
src/ptserver/ptserver.h
src/ptserver/ptuser.c
src/ptserver/ptutils.c
src/ptserver/utils.c

index 5562757..8f54608 100644 (file)
@@ -27,6 +27,8 @@ AC_ARG_ENABLE( largefile-fileserver,
 [  --enable-largefile-filesever         enable large file support in fileserver],, enable_largefile_fileserver="no")
 AC_ARG_ENABLE( namei-fileserver,
 [  --enable-namei-fileserver           force compilation of namei fileserver in preference to inode fileserver],, enable_namei_fileserver="no")
+AC_ARG_ENABLE( supergroups,
+[  --enable-supergroups                enable support for nested pts groups],, enable_supergroups="no")
 AC_ARG_ENABLE( fast-restart,
 [  --enable-fast-restart               enable fast startup of file server without salvaging],, enable_fast_restart="no")
 AC_ARG_ENABLE( bitmap-later,
@@ -606,6 +608,10 @@ if test "$enable_insecure" = "yes"; then
 fi
 
 # Fast restart
+if test "$enable_supergroups" = "yes"; then
+       AC_DEFINE(SUPERGROUPS, 1, [define if you want to have support for nested pts groups])
+fi
+
 if test "$enable_fast_restart" = "yes"; then
        AC_DEFINE(FAST_RESTART, 1, [define if you want to have fast restart])
 fi
index 4f52338..18434c4 100644 (file)
@@ -14,7 +14,7 @@ INCLS=${TOP_INCDIR}/ubik.h \
        ${TOP_INCDIR}/rx/xdr.h \
        ${TOP_INCDIR}/afs/keys.h \
        ${TOP_INCDIR}/afs/cellconfig.h \
-       ptserver.h ptclient.h ptint.h ptopcodes.h pterror.h
+       ptserver.h ptclient.h ptint.h ptopcodes.h pterror.h map.h
 
 LINCLS=${TOP_INCDIR}/ubik.h \
        ${TOP_INCDIR}/lock.h \
@@ -56,8 +56,8 @@ depinstall: \
 #
 # Build targets
 #
-ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a
-       $(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a map.o
+       $(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a
 
 ptserver.o: ptserver.c ${INCLS} AFS_component_version_number.c
 
@@ -67,6 +67,8 @@ ptprocs.o: ptprocs.c ${INCLS}
 
 utils.o: utils.c ${INCLS} 
 
+map.o: map.c ${INCLS}
+
 ptint.ss.o: ptint.ss.c ptint.xdr.c ptint.xg
 ptint.cs.o: ptint.cs.c ptint.xdr.c ptint.xg
 ptint.xdr.o: ptint.xdr.c ptint.h ptint.xg
@@ -144,8 +146,8 @@ testpt: testpt.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS)
 
 testpt.o: testpt.c ${INCLS} ${TOP_INCDIR}/afs/cmd.h AFS_component_version_number.c
 
-pt_util: pt_util.o ptutils.o ubik.o utils.o libprot.a $(LIBS)
-       $(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o libprot.a $(LIBS) ${XLIBS}
+pt_util: pt_util.o ptutils.o ubik.o utils.o map.o libprot.a $(LIBS)
+       $(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o libprot.a $(LIBS) ${XLIBS}
 
 ubik.o: ubik.c ${INCLS}
 
index 9081475..a4259c1 100644 (file)
 
 RCSID("$Header$");
 
+/*
+ *                      (3) Define a structure, idused, instead of an
+ *                          array of long integers, idmap, to count group
+ *                          memberships. These structures are on a linked
+ *                          list, with each structure containing IDCOUNT
+ *                          slots for id's.
+ *                      (4) Add new functions to processs the structure
+ *                          described above:
+ *                             zeromap(), idcount(), inccount().
+ *                      (5) Add code, primarily in WalkNextChain():
+ *                           1. Test id's, allowing groups within groups.
+ *                           2. Count the membership list for supergroups,
+ *                              and follow the continuation chain for
+ *                              supergroups.
+ *                      (6) Add fprintf statements for various error
+ *                          conditions.
+ */
+
 #include <afs/stds.h>
 #include <sys/types.h>
 #ifdef AFS_NT40_ENV
@@ -49,7 +67,6 @@ char *pr_dbaseName;
 char *whoami = "db_verify";
 #define UBIK_HEADERSIZE 64
 
-
 afs_int32 printheader(h)
      struct prheader *h;
 {
@@ -146,8 +163,17 @@ struct misc_data {
     afs_int32 maxId;                           /* user */
     afs_int32 minId;                           /* group */
     afs_int32 maxForId;                             /* foreign user id */
+#if defined(SUPERGROUPS)
+#define IDCOUNT 512
+    struct idused {
+       int idstart;
+       afs_int32 idcount[IDCOUNT];
+       struct idused *idnext;
+    } *idmap;
+#else
     int idRange;                       /* number of ids in map */
     afs_int32 *idmap;                  /* map of all id's: midId is origin */
+#endif /* SUPERGROUPS */
     int  nusers;                       /* counts of each type */
     int  ngroups;
     int  nforeigns;
@@ -164,6 +190,12 @@ struct misc_data {
     FILE *recreate;                    /* stream for recreate instructions */
 };
 
+#if defined(SUPERGROUPS)
+void  zeromap(struct idused *idmap);
+void inccount(struct idused **idmapp, int id);
+int   idcount(struct idused **idmapp, int id);
+#endif
+
 int readUbikHeader(misc)
   struct misc_data *misc;
 {
@@ -360,12 +392,21 @@ afs_int32 WalkNextChain (map, misc, ea, e)
     int i;
     int noErrors = 1;
     int length;                                /* length of chain */
+#if defined(SUPERGROUPS)
+    int sgcount;                       /* number of sgentrys */
+    afs_int32 sghead;
+#define g (((struct prentryg *)e))
+#endif
 
     if (e) {
        head = ntohl(e->next);
        eid = ntohl(e->id);
        bit = MAP_CONT;
        count = 0;                      /* set to >9999 if list ends early */
+#if defined(SUPERGROUPS)
+       sgcount = 0;
+       sghead = ntohl(g->next);
+#endif
        for (i=0; i<PRSIZE; i++) {
            afs_int32 id = ntohl(e->entries[i]);
            if (id == PRBADID) continue;
@@ -375,26 +416,124 @@ afs_int32 WalkNextChain (map, misc, ea, e)
                /* in case the ids are large, convert to pure sign. */
                if (id > 0) id_s = 1; else id_s = -1; 
                if (eid > 0) eid_s = 1; else eid_s = -1; 
+#if defined(SUPERGROUPS)
+               if (id_s > 0 && eid_s > 0) {
+                   fprintf (stderr,
+                            "User can't be member of user in membership list\n");
+                   if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+                   noErrors = 0;
+               }
+#else
                if (id_s * eid_s > 0) { /* sign should be different */
                    fprintf (stderr,
                             "Bad user/group dicotomy in membership list\n");
                    if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
                    noErrors = 0;
                }
+#endif /* SUPERGROUPS */
                /* count each user as a group, and each group a user is in */
+#if defined(SUPERGROUPS)
+               if (!(id < 0 && eid < 0) &&
+                   (id != ANONYMOUSID))
+                   inccount(&misc->idmap,id);
+#else
                if ((id >= misc->minId) && (id <= misc->maxId) &&
                    (id != ANONYMOUSID))
                    misc->idmap[id - misc->minId]++;
+#endif /* SUPERGROUPS */
            }
            else if (head) count=9999;
            else break;
        }
+#if defined(SUPERGROUPS)
+       sghead = g->nextsg;
+       if ((e->flags & PRGRP)) {
+           for (i = 0; i<SGSIZE; ++i) {
+               afs_int32 id = ntohl(g->supergroup[i]);
+               if (id == PRBADID) continue;
+               else if (id) {
+                   if (id > 0) {
+                       fprintf (stderr,
+                                "User can't be member of supergroup list\n");
+                       if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+                       noErrors = 0;
+                   }
+                   sgcount++;
+                   inccount(&misc->idmap, id);
+               }
+           }
+    }
+#endif /* SUPERGROUPS */
     }
     else {
        head = ntohl(cheader.freePtr);
+#if defined(SUPERGROUPS)
+       sghead = 0;
+#endif
        bit = MAP_FREE;
     }
 
+#if defined(SUPERGROUPS)
+    length = 0;
+    for (na=sghead; na; na=ntohl(c.next)) {
+       code = ConvertDiskAddress (na, &ni);
+       if (code) {
+           fprintf (stderr, "Bad continuation ptr %d", na);
+           if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+           if (na != sghead) {
+               fprintf (stderr, "last block: \n");
+               if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
+           }
+           return 0;
+       }
+       code = pr_Read (na, (char *)&c, sizeof(c));
+       if (code) return code;
+       length++;
+
+       if (map[ni]) {
+           fprintf (stderr, "Continuation entry reused\n");
+           if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+           if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
+           noErrors = 0;
+           break;
+       }
+       map[ni] |= bit;
+       if ((ntohl(c.id) != eid)) {
+           fprintf (stderr, "Continuation id mismatch\n");
+           if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+           if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
+           noErrors = 0;
+           continue;
+       }
+
+       /* update membership count */
+       for (i=0; i<COSIZE; i++) {
+           afs_int32 id = ntohl(c.entries[i]);
+           if (id == PRBADID) continue;
+           else if (id) {
+               int eid_s, id_s;
+               sgcount++;
+               /* in case the ids are large, convert to pure sign. */
+               if (id > 0) id_s = 1; else id_s = -1;
+               if (eid > 0) eid_s = 1; else eid_s = -1;
+               if (id_s > 0) {
+                   fprintf (stderr,
+                            "User can't be member of supergroup list\n");
+                   if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+                   if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
+                   noErrors = 0;
+               }
+               /* count each user as a group, and each group a user is in */
+               if (
+                   (id != ANONYMOUSID))
+                   inccount(&misc->idmap, id);
+           }
+           else if (c.next) count = 9999;
+           else break;
+       }
+    }
+    if (length > misc->maxContLength) misc->maxContLength = length;
+#endif /* SUPERGROUPS */
     length = 0;
     for (na=head; na; na=ntohl(c.next)) {
        code = ConvertDiskAddress (na, &ni);
@@ -440,6 +579,16 @@ afs_int32 WalkNextChain (map, misc, ea, e)
                /* in case the ids are large, convert to pure sign. */
                if (id > 0) id_s = 1; else id_s = -1; 
                if (eid > 0) eid_s = 1; else eid_s = -1; 
+#if defined(SUPERGROUPS)
+               if (id_s > 0 && eid_s > 0) {
+                   fprintf (stderr,
+                            "User can't be member of user in membership list\n"
+);
+                   if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+                   if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
+                   noErrors = 0;
+               }
+#else
                if (id_s * eid_s > 0) { /* sign should be different */
                    fprintf (stderr,
                             "Bad user/group dicotomy in membership list\n");
@@ -447,20 +596,39 @@ afs_int32 WalkNextChain (map, misc, ea, e)
                    if (PrintEntryError (misc, na, &c, 4)) return PRDBBAD;
                    noErrors = 0;
                }
+#endif /* SUPERGROUPS */
                /* count each user as a group, and each group a user is in */
+#if defined(SUPERGROUPS)
+               if (!(id < 0 && eid < 0) &&
+                   (id != ANONYMOUSID))
+                   inccount(&misc->idmap, id);
+#else
                if ((id >= misc->minId) && (id <= misc->maxId) &&
                    (id != ANONYMOUSID))
                    misc->idmap[id - misc->minId]++;
+#endif /* SUPERGROUPS */
            }
            else if (c.next) count = 9999;
            else break;
        }
     }
     if (e && noErrors && (count != ntohl(e->count))) {
+#if defined(SUPERGROUPS)
+       if (count >= 9999) fprintf (stderr, "Membership list ends early\n");
+#else
        if (count > 9999) fprintf (stderr, "Membership list ends early\n");
+#endif /* SUPERGROUPS */
        fprintf (stderr, "Count was %d should be %d\n",
                 count, ntohl(e->count));
        if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+#if defined(SUPERGROUPS)
+       noErrors = 0;
+    }
+    if (e && (e->flags & PRGRP) && (sgcount != ntohl(g->countsg))) {
+       fprintf (stderr, "SGCount was %d should be %d\n",
+                sgcount, ntohl(g->countsg));
+       if (PrintEntryError (misc, ea, e, 2)) return PRDBBAD;
+#endif
     }
 
     if (e) {
@@ -469,6 +637,9 @@ afs_int32 WalkNextChain (map, misc, ea, e)
     else misc->freeLength = length;
 
     return 0;
+#if defined(SUPERGROUPS)
+#undef g
+#endif
 }
 
 afs_int32 WalkOwnedChain (map, misc, ea, e)
@@ -598,7 +769,11 @@ afs_int32 WalkChains (map, misc)
            break;
          case PRUSER:
            if (id <= 0) {
+#if defined(SUPERGROUPS)
+               fprintf (stderr, "User id not positive\n");
+#else
                fprintf (stderr, "User id negative\n");
+#endif
                goto abort;
            }
 
@@ -673,10 +848,16 @@ afs_int32 GC (map, misc)
                if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
            }
            id = ntohl(e.id);
+#if defined(SUPERGROUPS)
+           if ((id != ANONYMOUSID) &&
+              ((refCount = idcount(&misc->idmap, id)) !=
+               ntohl(e.count))) {
+#else
            if ((id >= misc->minId) && (id <= misc->maxId) &&
                (id != ANONYMOUSID) &&
                ((refCount = misc->idmap[id - misc->minId]) !=
                 ntohl(e.count))) {
+#endif /* SUPERGROUPS */
                afs_int32 na;
                fprintf (stderr, "Entry membership count is inconsistent: %d entries refer to this one\n", refCount);
                if (PrintEntryError (misc, ea, &e, 2)) return PRDBBAD;
@@ -723,13 +904,21 @@ afs_int32 DumpRecreate (map, misc)
     char *name;
     int  builtinUsers = 0;
     int  createLow = 0;                        /* users uncreate from here */
+#if defined(SUPERGROUPS)
+    struct idused *idmap;              /* map of all id's */
+#else
     afs_int32 *idmap;                  /* map of all id's */
+#endif
     int found;    
     FILE *rc;
 
     rc = misc->recreate;
     idmap = misc->idmap;
+#if defined(SUPERGROUPS)
+    zeromap(idmap);
+#else
     memset(idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
+#endif
     do {
        found = 0;
        for (ei=createLow; ei<misc->nEntries; ei++) {
@@ -762,7 +951,11 @@ afs_int32 DumpRecreate (map, misc)
 
                /* check for duplicate id.  This may still lead to duplicate
                  * names. */
+#if defined(SUPERGROUPS)
+               if (idcount(&idmap, id)) {
+#else
                if (idmap[id-misc->minId]) {
+#endif
                    fprintf (stderr,
                             "Skipping entry with duplicate id %di\n", id);
                    goto user_done;
@@ -786,7 +979,11 @@ afs_int32 DumpRecreate (map, misc)
                    fprintf (stderr, "Warning: orphan group %s will become self owning.\n", name);
                    owner = id;
                }
+#if defined(SUPERGROUPS)
+               else if (!idcount(&idmap, owner)) goto user_skip;
+#else
                else if (idmap[owner-misc->minId] == 0) goto user_skip;
+#endif
 
                if (rc) fprintf (rc, "cr %s %d %d\n", name, id, owner);
                
@@ -806,7 +1003,11 @@ afs_int32 DumpRecreate (map, misc)
                }
 user_done:
                map[ei] |= MAP_RECREATE;
+#if defined(SUPERGROUPS)
+               if (id != ANONYMOUSID) inccount(&idmap, id);
+#else
                if (id != ANONYMOUSID) idmap[id-misc->minId]++;
+#endif
                found++;
            }
            /* bump low water mark if possible */
@@ -830,7 +1031,11 @@ user_skip:;
            name = QuoteName(e.name);
            fprintf (stderr, "Warning: group %s in self owning cycle\n", name);
            if (rc) fprintf (rc, "cr %s %d %d\n", name, id, id);
+#if defined(SUPERGROUPS)
+           inccount(&idmap, id);
+#else
            idmap[id-misc->minId]++;
+#endif
        }
     for (ei=0; ei<misc->nEntries; ei++)
        if (((map[ei] & MAP_HASHES) == MAP_HASHES) &&
@@ -840,7 +1045,11 @@ user_skip:;
            if (code) return code;
 
            owner = ntohl(e.owner);
+#if defined(SUPERGROUPS)
+           if (!idcount(&idmap, owner)) {
+#else
            if (idmap[owner-misc->minId] == 0) {
+#endif
                fprintf (stderr,
                         "Skipping chown of '%s' to non-existant owner %di\n",
                         e.name, owner);
@@ -864,17 +1073,56 @@ user_skip:;
            if ((id < 0) && (flags & PRGRP)) {
                int count = 0;
                afs_int32 na;
+#if defined(SUPERGROUPS)
+               afs_int32 ng;
+#endif
                int i;
                for (i=0; i<PRSIZE; i++) {
                    afs_int32 uid = ntohl(e.entries[i]);
                    if (uid == 0) break;
                    if (uid == PRBADID) continue;
+#if !defined(SUPERGROUPS)
                    if (uid > 0) {
+#endif
                        fprintf (rc, "au %d %d\n", uid, id);
                        count++;
+#if !defined(SUPERGROUPS)
                    } else fprintf (stderr,
                                    "Skipping %di in group %di\n", uid, id);
+#endif
+               }
+#if defined(SUPERGROUPS)
+#define g      (*((struct prentryg *)&e))
+               ng = ntohl(g.nextsg);
+               for (i=0; i<SGSIZE; i++) {
+                   afs_int32 uid = ntohl(g.supergroup[i]);
+                   if (uid == 0) break;
+                   if (uid == PRBADID) continue;
+                   fprintf (rc, "au %d %d\n", uid, id);
+                   count++;
                }
+               while (ng) { 
+                   struct prentry c;
+                   code = pr_Read (ng, (char *)&c, sizeof(c));
+                   if (code) return code;
+
+                   if ((id == ntohl(c.id)) && (ntohl(c.flags) & PRCONT)) {
+                       for (i=0; i<COSIZE; i++) {
+                           afs_int32 uid = ntohl(c.entries[i]);
+                           if (uid == 0) break;
+                           if (uid == PRBADID) continue;
+                               fprintf (rc, "au %d %d\n", uid, id);
+                               count++;
+                       }
+                   } else {
+                       fprintf (stderr,
+                                "Skipping continuation block at %d\n", ng);
+                       break;
+                   }
+                   ng = ntohl(c.next);
+               }
+#undef g
+#endif /* SUPERGROUPS */
                na = ntohl(e.next);
                while (na) {
                    struct prentry c;
@@ -886,12 +1134,16 @@ user_skip:;
                            afs_int32 uid = ntohl(c.entries[i]);
                            if (uid == 0) break;
                            if (uid == PRBADID) continue;
+#if !defined(SUPERGROUPS)
                            if (uid > 0) {
+#endif
                                fprintf (rc, "au %d %d\n", uid, id);
                                count++;
+#if !defined(SUPERGROUPS)
                            } else fprintf (stderr,
                                            "Skipping %di in group %di\n",
                                            uid, id);
+#endif
                        }
                    } else {
                        fprintf (stderr,
@@ -955,6 +1207,9 @@ afs_int32 CheckPrDatabase (misc)
     }
 
     /* hash walk calculates min and max id */
+#if defined(SUPERGROUPS)
+    misc->idmap = 0;
+#else
     n = ((misc->maxId > misc->maxForId) ? misc->maxId : misc->maxForId);
     misc->idRange = n - misc->minId + 1;
     misc->idmap = (afs_int32 *)malloc (misc->idRange * sizeof(afs_int32));
@@ -965,6 +1220,7 @@ afs_int32 CheckPrDatabase (misc)
        goto abort;
     }
     memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
+#endif /* SUPERGROUPS */
 
     if (misc->verbose) {
        printf ("\nChecking entry chains\n");
@@ -1114,3 +1370,64 @@ main (argc, argv)
 
   return cmd_Dispatch(argc, argv);
 }
+
+
+#if defined(SUPERGROUPS)
+
+/* new routines to deal with very large ID numbers */
+
+void zeromap(idmap)
+    struct idused *idmap;
+{
+    while (idmap) {
+       bzero((char*) idmap->idcount, sizeof idmap->idcount);
+       idmap = idmap->idnext;
+    }
+}
+
+void inccount(struct idused **idmapp, int id)
+{
+    struct idused *idmap;
+
+    if (IDCOUNT & (IDCOUNT-1)) {
+       fprintf(stderr,"IDCOUNT must be power of 2!\n");
+       exit(1);
+    }
+    while (idmap = *idmapp) {
+       if (idmap->idstart == (id & ~(IDCOUNT-1)))
+           break;
+       idmapp = &idmap->idnext;
+    }
+    if (!idmap) {
+       idmap = (struct idused *) malloc(sizeof *idmap);
+       if (!idmap) {
+           perror("idmap");
+           exit(1);
+       }
+       bzero((char*) idmap, sizeof idmap);
+       idmap->idstart = id & ~(IDCOUNT-1);
+       idmap->idnext = *idmapp;
+       *idmapp = idmap;
+    }
+    ++idmap->idcount[id & (IDCOUNT-1)];
+}
+
+int idcount(idmapp, id)
+    struct idused **idmapp;
+{
+    struct idused *idmap;
+
+    if (IDCOUNT & (IDCOUNT-1)) {
+       fprintf(stderr,"IDCOUNT must be power of 2!\n");
+       exit(1);
+    }
+    while (idmap = *idmapp) {
+           if (idmap->idstart == (id & ~(IDCOUNT-1))) {
+               return idmap->idcount[id & (IDCOUNT-1)];
+           }
+           idmapp = &idmap->idnext;
+    }
+    return 0;
+}
+
+#endif /* SUPERGROUPS */
index 8b66a69..38f4833 100644 (file)
@@ -120,13 +120,25 @@ int pr_PrintEntry (f, hostOrder, ea, e, indent)
                 host(e->nextID), host(e->nextName),
                 host(e->owner), host(e->creator));
        fprintf (f, "%*s", indent, "");
+#if defined(SUPERGROUPS)
+       fprintf (f, "quota groups %d, foreign users %d.  Mem: %d, cntsg: %d\n",
+               host(e->ngroups), host(e->nusers),
+               host(e->count), host(e->instance));
+#else
        fprintf (f, "quota groups %d, foreign users %d.  Mem: %d, inst: %d\n",
                 host(e->ngroups), host(e->nusers),
                 host(e->count), host(e->instance));
+#endif
        fprintf (f, "%*s", indent, "");
+#if defined(SUPERGROUPS)
+       fprintf (f, "Owned chain %d, next owned %d, nextsg %d, sg (%d %d).\n",
+               host(e->owned), host(e->nextOwned),
+               host(e->parent), host(e->sibling), host(e->child));
+#else
        fprintf (f, "Owned chain %d, next owned %d, inst ptrs(%d %d %d).\n",
                 host(e->owned), host(e->nextOwned),
                 host(e->parent), host(e->sibling), host(e->child));
+#endif
        fprintf (f, "%*s", indent, "");
        if (strlen (e->name) >= PR_MAXNAMELEN)
            fprintf (f, "NAME TOO LONG: ");
diff --git a/src/ptserver/map.c b/src/ptserver/map.c
new file mode 100644 (file)
index 0000000..a611eeb
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+ *     bit map routines (in-core).
+ */
+/*
+ * Copyright (c) 1995, 1996 Marcus D. Watts  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Marcus D. Watts.
+ * 4. The name of the developer may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * MARCUS D. WATTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+RCSID("$Header$");
+
+#ifdef SUPERGROUPS
+#include <errno.h>
+#include "map.h"
+char *malloc();
+
+#undef PRINT_MAP_ERROR
+/* #define MAP_DEBUG /**/
+/* #define NEED_READ_WRITE /**/
+
+#define LSHIFT 5
+#define MSHIFT 8       /* XXX make this 8 in the production version... */
+#define MDATA (1<<MSHIFT)
+struct bitmap {
+       struct bitmap *m_next;
+       int m_page;
+       long m_data[MDATA];
+};
+
+#define MAP(p) ((struct bitmap*)((long)(p)&~1))
+#define NEGMAP(p)      (((int)(p))&1)
+#define POSMAP(p)      (!NEGMAP(p))
+#define NOT_MAP(mp)    ((struct map *) (((long)(mp)) ^ 1))
+
+#define NUMBERTOBIT(n) ((n) & ((1<<LSHIFT)-1))
+#define NUMBERTOINDEX(n)       ((n>>LSHIFT) & ((1<<MSHIFT)-1))
+#define NUMBERTOPAGE(n)        ((n>>(LSHIFT+MSHIFT)))
+#define TONUMBER(p,x,b)        ((b) + ((x)<<LSHIFT) + ((p)<<((LSHIFT+MSHIFT))))
+
+#define Mflag  (debug_mask & (1L<<('Y'-'@')))
+#define Aflag  (debug_mask & (1L<<('Z'-'@')))
+extern int debug_mask;
+
+#if __STDC__
+int in_map(struct map *parm, long node)
+#else
+int in_map(parm, node)
+       struct map *parm;
+       long node;
+#endif
+{
+       struct bitmap *map;
+       long bit;
+       int x, page;
+       int result;
+
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf ("in_map: is %d in [", node);
+print_map(parm);
+printf (" ]");
+}
+#endif
+       bit = NUMBERTOBIT(node);
+       x = NUMBERTOINDEX(node);
+       page = NUMBERTOPAGE(node);
+#ifdef MAP_DEBUG
+if (Aflag)
+if (TONUMBER(page,x,bit) != node)
+{
+printf ("bxp mixup: node=%ld -> p=%d x=%d b=%d -> %ld, %ld, %ld = %ld\n",
+node,
+page,
+x,
+bit,
+TONUMBER(page,0,0),
+TONUMBER(0,x,0),
+TONUMBER(0,0,bit),
+TONUMBER(page,x,bit));
+}
+#endif
+       bit = 1L<<bit;;
+
+       for (map = MAP(parm); map; map = map->m_next)
+               if (map->m_page == page)
+                       return NEGMAP(parm) ^ (!!(map->m_data[x] & bit));
+       result = !POSMAP(parm);
+#ifdef MAP_DEBUG
+if (Aflag)
+printf (" -> %s\n", result ? "yes" : "no");
+#endif
+       return result;
+}
+
+void
+free_map(parm)
+       struct map *parm;
+{
+       struct bitmap *map, *next;
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf ("Freeing map");
+print_map(parm);
+printf ("\n");
+}
+#endif
+       map = MAP(parm);
+       while (map) {
+               next = map->m_next;
+               free(map);
+               map = next;
+       }
+}
+
+struct map *add_map(parm, node)
+       struct map *parm;
+       long node;
+{
+       struct bitmap *map;
+       long bit;
+       int x, page;
+
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf ("add_map: adding %d to [", node);
+print_map(parm);
+printf (" ] ");
+}
+#endif
+       bit = NUMBERTOBIT(node);
+       x = NUMBERTOINDEX(node);
+       page = NUMBERTOPAGE(node);
+
+       bit = 1L<<bit;;
+
+       for (map = MAP(parm); map; map = map->m_next)
+               if (map->m_page == page)
+                       break;
+       if (!map) {
+               map = (struct bitmap *) malloc(sizeof *map);
+               if (!map) {
+#ifdef PRINT_MAP_ERROR
+printf ("No memory!\n"); 
+#endif
+                       free_map((struct map *) map);
+                       return 0;
+               }
+               map->m_page = page;
+               bzero((char*) map->m_data, sizeof map->m_data);
+               if (NEGMAP(parm))
+               {
+                       int i;
+                       for (i = 0; i < MDATA; ++i)
+                               map->m_data[i] = ~0;
+               }
+               map->m_next = MAP(parm);
+               if (POSMAP(parm))
+                       parm = (struct map *) map;
+               else
+                       parm = NOT_MAP(map);
+       }
+       if (POSMAP(parm))
+               map->m_data[x] |= bit;
+       else
+               map->m_data[x] &= ~bit;
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf (" ->");
+print_map(parm);
+printf ("\n");
+}
+#endif
+       return (struct map *) parm;
+}
+
+struct bitmap *
+simplify_bitmap(map)
+       struct bitmap *map;
+{
+       struct bitmap **mpp, *mp2;
+       int i;
+       for (mpp = &map; mp2 = *mpp; )
+       {
+               for (i = 0; i < MDATA; ++i)
+                       if (map->m_data[i])
+                               break;
+               if (i == MDATA) {
+#ifdef PRINT_MAP_ERROR
+printf ("simplify_bitmap: failed to eliminate zero page %d\n", mp2->m_page);
+#endif
+                       *mpp = mp2->m_next;
+                       free((char*)mp2);
+               }
+               else mpp = &mp2->m_next;
+       }
+       return map;
+}
+
+struct bitmap *or_bitmap(left, right)
+       struct bitmap *left, *right;
+{
+       struct bitmap **rightmp, *lmap, *rmap;
+       int i;
+       for (lmap = left; lmap; lmap = lmap->m_next)
+       {
+               for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next)
+                       if (rmap->m_page == lmap->m_page)
+                       {
+                               for (i = 0; i < MDATA; ++i)
+                                       lmap->m_data[i] |= rmap->m_data[i];
+                               *rightmp = rmap->m_next;
+                               free((char*)rmap);
+                               break;
+                       }
+       }
+       for (rightmp = &left; *rightmp; rightmp = &(*rightmp)->m_next)
+               ;
+       *rightmp = right;
+       return left;
+}
+
+struct bitmap *and_bitmap(left, right)
+       struct bitmap *left, *right;
+{
+       struct bitmap **rightmp, *lmap, *rmap, **leftmp;
+       int i;
+       long sig;
+       for (leftmp = &left; lmap = *leftmp; )
+       {
+               sig = 0;
+               for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next)
+                       if (rmap->m_page == lmap->m_page)
+                       {
+                               for (i = 0; i < MDATA; ++i)
+                                       sig |= (lmap->m_data[i] &= rmap->m_data[i]);
+                               *rightmp = rmap->m_next;
+                               free((char*)rmap);
+                               break;
+                       }
+               if (rmap && sig)
+               {
+                       leftmp = &lmap->m_next;
+               } else {
+                       *leftmp = lmap->m_next;
+                       free((char*)lmap);
+               }
+       }
+       free_map((struct map *) right);
+       return simplify_bitmap(left);
+}
+
+/* bit set in left, but not in right */
+struct bitmap *bic_bitmap(left, right)
+       struct bitmap *left, *right;
+{
+       struct bitmap **rightmp, *lmap, *rmap, **leftmp;
+       int i;
+       long sig;
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("bic_bitmap: left=%#lx right=%#lx\n", left, right);
+}
+#endif
+       for (leftmp = &left; lmap = *leftmp; )
+       {
+               sig = 0;
+               for (rightmp = &right; rmap = *rightmp; rightmp = &rmap->m_next)
+                       if (rmap->m_page == lmap->m_page)
+                       {
+                               for (i = 0; i < MDATA; ++i)
+                                       sig |= (lmap->m_data[i] &= ~rmap->m_data[i]);
+                               *rightmp = rmap->m_next;
+                               free((char*)rmap);
+                               break;
+                       }
+               if (!rmap || sig)
+               {
+                       leftmp = &lmap->m_next;
+               } else {
+                       *leftmp = lmap->m_next;
+                       free((char*)lmap);
+               }
+       }
+       free_map((struct map *) right);
+       left = simplify_bitmap(left);
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("bic_bitmap: result=%#lx\n", left);
+}
+#endif
+       return left;
+}
+
+struct map *and_map(mp1, mp2)
+       struct map *mp1, *mp2;
+{
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("Anding maps");
+print_map(mp1);
+printf (" and");
+print_map(mp2);
+}
+#endif
+       if (POSMAP(mp1))
+               if (POSMAP(mp2))
+                       mp1 = (struct map *) and_bitmap(mp1, mp2);
+               else
+                       mp1 = (struct map *) bic_bitmap(mp1, MAP(mp2));
+       else
+               if (POSMAP(mp2))
+                       mp1 = (struct map *) bic_bitmap(mp2, MAP(mp1));
+               else
+                       mp1 =  NOT_MAP(or_bitmap(MAP(mp1), MAP(mp2)));
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf (" ->");
+print_map(mp1);
+printf ("\n");
+}
+#endif
+       return mp1;
+}
+
+struct map *or_map(mp1, mp2)
+       struct map *mp1, *mp2;
+{
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("Oring maps");
+print_map(mp1);
+printf (" and");
+print_map(mp2);
+}
+#endif
+       if (POSMAP(mp1))
+               if (POSMAP(mp2))
+                       mp1 = (struct map *) or_bitmap(mp1, mp2);
+               else
+                       mp1 = NOT_MAP(bic_bitmap(MAP(mp2), mp1));
+       else
+               if (POSMAP(mp2))
+                       mp1 = NOT_MAP(bic_bitmap(MAP(mp1), mp2));
+               else
+                       mp1 = NOT_MAP(and_bitmap(MAP(mp1), MAP(mp2)));
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf (" ->");
+print_map(mp1);
+printf ("\n");
+}
+#endif
+       return mp1;
+}
+
+struct map *not_map(map)
+       struct map *map;
+{
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("Notting map");
+print_map(map);
+printf ("\n");
+}
+#endif
+       return NOT_MAP(map);
+}
+
+struct map *copy_map(parm)
+       struct map *parm;
+{
+       struct bitmap *result, **mpp, *map;
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("copymap:");
+print_map(parm);
+printf ("\n");
+}
+#endif
+       map = MAP(parm);
+       for (mpp = &result; *mpp = 0, map; map = map->m_next) {
+               *mpp = (struct bitmap *) malloc(sizeof **mpp);
+               if (!*mpp) {
+#ifdef MAP_DEBUG
+if (Mflag)
+printf ("copy_map: out of memory\n");
+#endif
+                       free_map((struct map *) result);
+                       result = 0;
+                       break;
+               }
+               **mpp = *map;
+               mpp = &(*mpp)->m_next;
+       }
+       if (NEGMAP(parm))
+               return NOT_MAP(result);
+       else
+               return (struct map*) result;
+}
+
+long
+count_map(parm)
+       struct map *parm;
+{
+       long nf;
+       struct bitmap *map;
+       register i, j;
+
+       nf = 0;
+       for (map = MAP(parm); map; map = map->m_next)
+       {
+               for (i = 0; i < MDATA; ++i)
+               {
+                       if (!map->m_data[i])
+                               ;
+                       else if (!~map->m_data[i])
+                               nf += (1<<LSHIFT);
+                       else for (j = 0; j < (1L<<LSHIFT); ++j)
+                               if (map->m_data[i] & (1L<<j))
+                                       ++nf;
+               }
+       }
+       if (NEGMAP(parm))
+               nf = ~nf;       /* note 1's complement */
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("countmap:");
+print_map(parm);
+printf (" -> %d\n", nf);
+}
+#endif
+       return nf;
+}
+
+long
+next_map(parm, node)
+       struct map *parm;
+       long node;
+{
+       struct bitmap *map, *lowest;
+       long bit, mask;
+       int x, page;
+       int best;
+       int i;
+       int bn;
+
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf ("next_map: selecting next after %d from", node);
+print_map(parm);
+}
+#endif
+       if (NEGMAP(parm)) {
+#ifdef MAP_DEBUG
+if (Aflag)
+printf ("next_map failed; negative map\n");
+#endif
+               return -1;
+       }
+
+       ++node;
+       bit = NUMBERTOBIT(node);
+       x = NUMBERTOINDEX(node);
+       page = NUMBERTOPAGE(node);
+       bit = 1L<<bit;
+       best = -1;
+       lowest = 0;
+       for (map = MAP(parm); map; map = map->m_next)
+               if (map->m_page >= page && (!lowest || lowest->m_page > map->m_page))
+               {
+                       i = 0; mask = ~0;
+                       if (page == map->m_page) i = x, mask = -bit;
+                       for (; i < MDATA; ++i, mask = ~0)
+                               if (map->m_data[i] & mask) break;
+                       if (i < MDATA) {
+                               for (bn = 0; bn < (1<<LSHIFT); ++bn)
+                                       if (map->m_data[i]&mask&(1L<<bn)) {
+                                               break;
+                                       }
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+if (bn == (1<<LSHIFT)){
+printf ("next_map: botch; pageno %d index %d data %#lx mask %#lx x,bit %d,%#lx\n",
+map->m_page,
+i,
+map->m_data[i],
+mask,
+x,bit);
+continue;
+}
+}
+#endif
+                               best = bn + ((i+((map->m_page)<<MSHIFT)
+                                       ) << LSHIFT);
+                               lowest = map;
+                       }
+               }
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf (" -> %d\n", best);
+if (best >= 0 && !in_map((struct map *) parm, best)) {
+printf ("next_map: botch; %d not in map\n", best);
+return -1;
+}
+}
+#endif
+       return best;
+}
+
+long
+first_map(parm)
+       struct map *parm;
+{
+       return next_map(parm, -9999);
+}
+
+long
+prev_map(parm, node)
+       struct map *parm;
+       long node;
+{
+       struct bitmap *map, *lowest;
+       long bit, mask;
+       int x, page;
+       int best;
+       int i;
+       int bn;
+
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf ("prev_map: selecting previous before %d from", node);
+print_map(parm);
+}
+#endif
+       if (NEGMAP(parm)) {
+#ifdef MAP_DEBUG
+if (Aflag)
+printf ("prev_map failed; negative map\n");
+#endif
+               return -1;
+       }
+
+       if (node < 0)
+               node = ((unsigned long)~0)>>1;
+
+       --node;
+       bit = NUMBERTOBIT(node);
+       x = NUMBERTOINDEX(node);
+       page = NUMBERTOPAGE(node);
+       bit = 1L<<bit;
+       best = -1;
+       lowest = 0;
+       for (map = MAP(parm); map; map = map->m_next)
+               if (map->m_page <= page && (!lowest || lowest->m_page < map->m_page))
+               {
+                       i = MDATA-1; mask = ~0;
+                       if (page == map->m_page) i = x, mask = (bit<<1)-1;
+                       for (; i >= 0; --i, mask = ~0)
+                               if (map->m_data[i] & mask) break;
+                       if (i >= 0) {
+                               for (bn = (1<<LSHIFT)-1; bn >= 0; --bn)
+                                       if (map->m_data[i]&mask&(1L<<bn)) {
+                                               break;
+                                       }
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+if (bn < 0){
+printf ("prev_map: botch; pageno %d index %d data %#lx mask %#lx x,bit %d,%#lx\n",
+map->m_page,
+i,
+map->m_data[i],
+mask,
+x,bit);
+continue;
+}
+}
+#endif
+                               best = bn + ((i+((map->m_page)<<MSHIFT)
+                                       ) << LSHIFT);
+                               lowest = map;
+                       }
+               }
+#ifdef MAP_DEBUG
+if (Aflag)
+{
+printf (" -> %d\n", best);
+if (best >= 0 && !in_map(parm, best)) {
+printf ("prev_map: botch; %d not in map\n", best);
+return -1;
+}
+}
+#endif
+       return best;
+}
+
+long
+last_map(parm)
+       struct map *parm;
+{
+       return prev_map(parm, 0x7fffffff);
+}
+
+struct map *negative_map(map)
+       struct map *map;
+{
+       return (struct map *) NEGMAP(map);
+}
+
+struct map *bic_map(mp1, mp2)
+       struct map *mp1, *mp2;
+{
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf ("Bic maps");
+print_map(mp1);
+printf (" minus");
+print_map(mp2);
+}
+#endif
+       mp1 = and_map(mp1, NOT_MAP(mp2));
+#ifdef MAP_DEBUG
+if (Mflag)
+{
+printf (" ->");
+print_map(mp1);
+printf ("\n");
+}
+#endif
+       return mp1;
+}
+
+#ifdef PRINT_MAP_ERROR
+print_map(parm)
+       struct map *parm;
+{
+       struct bitmap *map;
+       int i, j;
+       int bitno, firstbitno, lastbitno;
+       if (NEGMAP(parm)) {
+               printf (" NOT");
+       }
+       map = MAP(parm);
+       if (!map)
+               printf (" nil(%lx)", parm);
+else printf (" %lx", parm);
+       lastbitno = -100;
+       firstbitno = -100;
+       for (; map; map = map->m_next)
+               for (i = 0; i < MDATA; ++i)
+                       if (map->m_data[i])
+                               for (j = 0; j < (1<<LSHIFT); ++j)
+                               {
+                                       bitno = j+
+                                               (i<<LSHIFT)+
+                                               ((map->m_page)<<(LSHIFT+MSHIFT));
+                                       if (map->m_data[i] & (1<<j))
+                                       {
+                                               if (bitno == lastbitno + 1)
+                                               {
+                                                       ++lastbitno;
+                                                       continue;
+                                               }
+                                               if (bitno != (lastbitno + 1)) {
+                                                       if (firstbitno >= 0
+                                                       && firstbitno != lastbitno)
+                                                       printf ("-%d", lastbitno);
+                                                       firstbitno = -100;
+                                               }
+                                               printf (" %d",
+                                                       bitno);
+                                               firstbitno = lastbitno = bitno;
+                                       } else {
+                                               if (firstbitno >= 0 && firstbitno != lastbitno)
+                                                       printf ("-%d", lastbitno);
+                                               firstbitno = -100;
+                                       }
+                               }
+       if (firstbitno >= 0 && firstbitno != lastbitno)
+               printf ("-%d", lastbitno);
+}
+#endif
+
+#ifdef NEED_READ_WRITE
+struct map *
+read_map(f, arg)
+       int (*f)();
+       char *arg;
+{
+       struct bitmap *map, *result, **mp;
+       int page;
+       int bitno, lastno, thisno, prevno;
+       int i, j;
+       int data;
+
+/* count, then startbitno, then bits. */
+       lastno = ((*f)(arg));
+       if (lastno == -1)
+               return 0;
+       if (lastno & ((1<<LSHIFT)-1))
+       {
+#ifdef PRINT_MAP_ERROR
+               printf ("read_map: bad count\n");
+#endif
+               return 0;
+       }
+       bitno = ((*f)(arg));
+       if (bitno & ((1<<LSHIFT)-1))
+       {
+#ifdef PRINT_MAP_ERROR
+               printf ("read_map: bad start\n");
+#endif
+               return 0;
+       }
+       lastno += bitno;
+       map = result = 0;
+       for (; bitno < lastno; bitno += (1<<LSHIFT))
+       {
+               data = (*f)(arg);
+               if (!data) continue;
+               page = NUMBERTOPAGE(bitno);
+               if (!map || map->m_page != page)
+                       for (mp = &result; map = *mp; mp = &map->m_next)
+                               if (map->m_page == page)
+                                       break;
+               if (!map)
+               {
+                       map = (struct bitmap *) malloc(sizeof *map);
+                       if (!map) {
+#ifdef PRINT_MAP_ERROR
+printf ("No memory!\n"); 
+#endif
+                               if (result)
+                                       free_map((struct map *) result);
+                               return 0;
+                       }
+                       bzero((char*) map->m_data, sizeof map->m_data);
+                       map->m_page = page;
+                       map->m_next = 0;
+                       *mp = map;
+               }
+               map->m_data[NUMBERTOINDEX(bitno)] = data;
+       }
+       return (struct map *) result;
+}
+
+write_map(parm, f, arg)
+       struct map *parm;
+       int (*f)();
+       char *arg;
+{
+       struct bitmap *map;
+       int page;
+       int bitno, lastno, thisno, prevno;
+       int i, j;
+
+       bitno = first_map(parm);
+       bitno &= ~((1<<LSHIFT)-1);
+
+       lastno = last_map(parm);
+       lastno -= bitno;
+       lastno += ((1<<LSHIFT));
+       lastno &= ~((1<<LSHIFT)-1);
+/* count, then startbitno, then bits. */
+       if ((*f)(arg, lastno) == -1)
+               return -1;
+       /* word: number of bits */
+       if ((*f)(arg, bitno) == -1)
+               return -1;
+       lastno += bitno;
+       prevno = bitno;
+       for (bitno = first_map(parm); bitno >= 0; bitno = next_map(parm, bitno))
+       {
+               page = NUMBERTOPAGE(bitno);
+               for (map = MAP(parm); map; map = map->m_next)
+                       if (map->m_page == page)
+                               break;
+               if (!map)
+               {
+#ifdef PRINT_MAP_ERROR
+printf ("write_map: botch #1: can't find page %d\n", page);
+#endif
+continue;
+               }
+               for (i = 0; i < MDATA; ++i)
+               {
+                       if (!map->m_data[i])
+                               continue;
+                       thisno = TONUMBER(page, i, 0);
+                       for (j = thisno - prevno; j > 0; j -= (1<<LSHIFT))
+                               if ((*f)(arg, 0) == -1)
+                                       return -1;
+                       prevno = thisno;
+                       for (;;)
+                       {
+                               if ((*f)(arg, map->m_data[i]) == -1)
+                                       return -1;
+                               prevno += (1<<LSHIFT);
+                               ++i;
+                               if (i >= MDATA || !map->m_data[i])
+                                       break;
+                       }
+                       --i;
+               }
+               bitno = TONUMBER(page, i, 0)-1;
+       }
+#ifdef PRINT_MAP_ERROR
+if (prevno != lastno)
+printf ("write_map: botch #2: bitno=%d prevno=%d lastno=%d\n", bitno, prevno, lastno);
+#endif
+       return 0;
+}
+#endif
+
+#endif
diff --git a/src/ptserver/map.h b/src/ptserver/map.h
new file mode 100644 (file)
index 0000000..92f2fa4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *     map.h - header routines for in-core bitmap routines.
+ */
+/*
+ * Copyright (c) 1995 Marcus D. Watts  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Marcus D. Watts.
+ * 4. The name of the developer may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * MARCUS D. WATTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct map;
+
+int in_map(struct map *, long);
+void free_map(struct map *);
+struct map *add_map(struct map *, long);
+struct map *and_map(struct map *, struct map *);
+struct map *or_map(struct map *, struct map *);
+struct map *not_map(struct map *);
+struct map *copy_map(struct map *);
+long count_map(struct map *);
+long next_map(struct map *, long);
+long first_map(struct map *);
+long prev_map(struct map *, long);
+long last_map(struct map *);
+struct map *negative_map(struct map *);
+struct map *bic_map(struct map *, struct map *);
+int print_map(struct map *);
index 92a49ec..9f6364c 100644 (file)
@@ -387,6 +387,28 @@ char **argv;
            else code = ubik_Call(PR_RemoveFromGroup,pruclient,0,id,gid);
            if (CodeOk(code)) printf("%s\n",pr_ErrorMsg(code));
        }
+#if defined(SUPERGROUPS)
+       else if (!strcmp(op,"lsg")) {
+           alist.prlist_len = 0;
+           alist.prlist_val = 0;
+           /* scanf("%d",&id); */
+           if (GetInt32 (&id)) code = PRBADARG;
+           else code = ubik_Call(PR_ListSuperGroups,pruclient,0,id, &alist, &over);
+           if (CodeOk(code)) printf("%s\n",pr_ErrorMsg(code));
+           if (code == PRSUCCESS) {
+               ptr = alist.prlist_val;
+               if (over) {
+                   printf("Number of groups greater than PR_MAXGROUPS!\n");
+                   printf("Excess of %d.\n",over);
+               }
+               for (i=0;i<alist.prlist_len;i++,ptr++)
+                   printf("%d\n",*ptr);
+               free(alist.prlist_val);
+               alist.prlist_len = 0;
+               alist.prlist_val = 0;
+           }
+       }
+#endif /* SUPERGROUPS */
        else if (!strcmp(op,"l")) {
            alist.prlist_len = 0;
            alist.prlist_val = 0;
@@ -432,6 +454,28 @@ char **argv;
                alist.prlist_val = 0;
            }
        }
+#if defined(SUPERGROUPS)
+       else if (!strcmp(op,"m")) {
+           alist.prlist_len = 0;
+           alist.prlist_val = 0;
+           /* scanf("%d",&id); */
+           if (GetInt32 (&id)) code = PRBADARG;
+           else code = ubik_Call(PR_ListElements,pruclient,0,id, &alist, &over);
+           if (CodeOk(code)) printf("%s\n",pr_ErrorMsg(code));
+           if (code == PRSUCCESS) {
+               ptr = alist.prlist_val;
+               if (over) {
+                   printf("Number of groups greater than PR_MAXGROUPS!\n");
+                   printf("Excess of %d.\n",over);
+               }
+               for (i=0;i<alist.prlist_len;i++,ptr++)
+                   printf("%d\n",*ptr);
+               free(alist.prlist_val);
+               alist.prlist_len = 0;
+               alist.prlist_val = 0;
+           }
+       }
+#endif /* SUPERGROUPS */
        else if (!strcmp(op,"nu")) {
            /* scanf("%s",name); */
            if (GetString (name, sizeof(name))) code = PRBADARG;
@@ -535,6 +579,60 @@ char **argv;
                continue;
            }
        }
+#if defined(SUPERGROUPS)
+       else if (!strcmp(op,"fih")) {
+           char tname[128];
+           struct PrUpdateEntry uentry;
+           bzero(&uentry, sizeof(uentry));
+           /* scanf("%s",name); */
+           if (GetString (name, sizeof(name))) {
+               code = PRBADARG; 
+               continue;
+           }
+           code = pr_SNameToId(name,&id);
+           if (CodeOk(code)) {
+               printf("%s\n",pr_ErrorMsg(code));
+               continue;
+           }
+           code = pr_SIdToName(id, tname);
+           if (code == PRSUCCESS) {
+               printf("Warning: Id hash for %s (id %d) seems correct at the db; rehashing it anyway\n", name, id);
+/*             continue;*/
+           }
+           uentry.Mask = PRUPDATE_IDHASH;
+           code = ubik_Call(PR_UpdateEntry, pruclient, 0,0,name,&uentry);
+           if (code) {
+               printf("Failed to update entry %s (err=%d)\n", name, code);
+               continue;
+           }
+       }
+       else if (!strcmp(op,"fnh")) {
+           int tid;
+           struct PrUpdateEntry uentry;
+           bzero(&uentry, sizeof(uentry));
+           /* scanf("%d", &id); */
+           if (GetInt32 (&id)) {
+               code = PRBADARG;
+               continue;
+           }
+           code = pr_SIdToName(id, name);
+           if (CodeOk(code)) {
+               printf("%s\n",pr_ErrorMsg(code));
+               continue;
+           }
+           code = pr_SNameToId(name, &tid);
+           if (code == PRSUCCESS) {
+               printf("Name hash for %d (name is %s) seems correct at the db; rehashing it anyway\n", id, name);
+/*             continue;*/
+           }
+           uentry.Mask = PRUPDATE_NAMEHASH;
+           code = ubik_Call(PR_UpdateEntry, pruclient, 0,id,"_foo_",&uentry);
+           if (code) {
+               printf("Failed to update entry with id %d (err=%d)\n", id, code);
+               continue;
+           }
+       }
+#endif /* SUPERGROUPS */
        else if (!strcmp(op,"?")) 
            PrintHelp();
        else if (!strcmp(op,"q")) exit(0);
@@ -556,6 +654,10 @@ PrintHelp()
     printf("rm id gid - remove user id from group gid.\n");
     printf("l id - get the CPS for id.\n");
     printf("lh host - get the host CPS for host.\n");
+#if defined(SUPERGROUPS)
+    printf("lsg id - get the supergroups for id.\n");
+    printf("m id - list elements for id.\n");
+#endif
     printf("nu name - create new user with name - returns an id.\n");
     printf("ng name - create new group with name - returns an id.\n");
     printf("lm  - list max user id and max (really min) group id.\n");
index 1956d2b..92d14db 100644 (file)
@@ -42,5 +42,8 @@ extern int PR_ListOwned();
 extern int PR_GetCPS2();
 extern int PR_GetHostCPS();
 extern int PR_UpdateEntry();
+#if defined(SUPERGROUPS)
+extern int PR_ListSuperGroups();
+#endif
 
 #define pr_ErrorMsg error_message
index 4f453ee..6b941cd 100644 (file)
@@ -7,6 +7,17 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+/*
+ *                      Transarc does not currently use opcodes past 520, but
+ *                      they *could* decide at any time to use more opcodes.
+ *                      If they did, then one part of our local mods,
+ *                      ListSupergroups, would break.  I've therefore
+ *                      renumbered it to 530, and put logic in to enable the
+ *                      old opcode to work (for now).
+ *
+ */
+
+
 package PR_
 prefix S
 statindex 8
@@ -227,3 +238,32 @@ ListEntries(
   OUT prentries *bulkentries,
   OUT afs_int32     *nextstartindex
 ) = PRLISTENTRIES;
+
+#if defined(SUPERGROUPS)
+/*
+ *
+ * Dummy stubs for "reserved to Transarc" opcodes; just so
+ * that ptint.ss.c uses nicer function table.
+ */
+%#define PR_Pr523(call) (RXGEN_OPCODE)
+%#define PR_Pr524(call) (RXGEN_OPCODE)
+%#define PR_Pr525(call) (RXGEN_OPCODE)
+%#define PR_Pr526(call) (RXGEN_OPCODE)
+%#define PR_Pr527(call) (RXGEN_OPCODE)
+%#define PR_Pr528(call) (RXGEN_OPCODE)
+%#define PR_Pr529(call) (RXGEN_OPCODE)
+Pr523()=523;
+Pr524()=524;
+Pr525()=525;
+Pr526()=526;
+Pr527()=527;
+Pr528()=528;
+Pr529()=529;
+
+ListSuperGroups(
+  IN long id,
+  OUT prlist *elist,
+  OUT long *over
+) = PRLISTSUPERGROUPS;
+
+#endif 
index 40c0af7..d25fca7 100644 (file)
@@ -30,5 +30,5 @@
 #define PRGETHOSTCPS 519
 #define PRUPDATEENTRY 520
 #define PRLISTENTRIES 521
-#define HIGHEST_OPCODE 521
-
+#define PRLISTSUPERGROUPS 530
+#define HIGHEST_OPCODE 530
index 363cdbc..e9613ec 100644 (file)
@@ -7,6 +7,46 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+/*
+ *                      (3) function addToGroup
+ *
+ *                          1. Eliminate the code that tests for adding groups
+ *                             to groups. This is an error in normal AFS.
+ *                          2. If adding a group to a group call AddToSGEntry
+ *                             to add the id of the group it's a member of.
+ *                      
+ *                      (4) function Delete
+ *
+ *                          1. Print a messsage if an error is returned from
+ *                             FindByID() and PTDEBUG is defined. 
+ *                          2. If removing a group from a group call   
+ *                             RemoveFromSGEntry to remove the id of the  
+ *                             group it's a member of.            
+ *                          3. Remove supergroup continuation records.
+ *
+ *                      (5) function RemoveFromGroup 
+ *               
+ *                          1. Eliminate the code that tests for adding groups
+ *                             to groups. This is an error in normal AFS. 
+ *                          2. If removing a group from a group call 
+ *                             RemoveFromSGEntry to remove the id of the 
+ *                             group it's a member of.
+ *
+ *                      (6) Add new functions PR_ListSuperGroups and 
+ *                          listSuperGroups.
+ *                      
+ *                      (7) function isAMemberOf
+ *                      
+ *                          1. Allow groups to be members of groups.
+ *
+ *                      Transarc does not currently use opcodes past 520, but
+ *                      they *could* decide at any time to use more opcodes.
+ *                      If they did, then one part of our local mods,
+ *                      ListSupergroups, would break.  I've therefore
+ *                      renumbered it to 530, and put logic in to enable the
+ *                      old opcode to work (for now).
+ */
+
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -54,6 +94,10 @@ afs_int32 getCPS(), getCPS2(), getHostCPS(), listMax(), setMax(), listEntry();
 afs_int32 listEntries(), changeEntry(), setFieldsEntry(), put_prentries();
 afs_int32 listElements(), listOwned(), isAMemberOf(), idToName();
 
+#if defined(SUPERGROUPS)
+afs_int32 listSuperGroups();
+#endif
+
 static stolower();
 extern int IDCmp();
 
@@ -419,8 +463,12 @@ afs_int32 gid;
     memset(&uentry, 0, sizeof(uentry));
     code = pr_ReadEntry(tt,0,tempu,&uentry);
     if (code != 0)  ABORT_WITH(tt,code);
+
+#if !defined(SUPERGROUPS)
     /* we don't allow groups as members of groups at present */
     if (uentry.flags & PRGRP) ABORT_WITH(tt,PRNOTUSER);
+#endif
+
     tempg = FindByID(tt,gid);
     if (!tempg) ABORT_WITH(tt,PRNOENT);
     code = pr_ReadEntry(tt,0,tempg,&tentry);
@@ -431,6 +479,12 @@ afs_int32 gid;
     
     code = AddToEntry (tt, &tentry, tempg, aid);
     if (code != PRSUCCESS) ABORT_WITH(tt,code);
+
+#if defined(SUPERGROUPS)
+    if (uentry.flags & PRGRP)
+      code = AddToSGEntry (tt, &uentry, tempu, gid); /* mod group to be in sg */
+    else
+#endif
     /* now, modify the user's entry as well */
     code = AddToEntry (tt, &uentry, tempu, gid);
     if (code != PRSUCCESS) ABORT_WITH(tt,code);
@@ -615,6 +669,11 @@ afs_int32 Delete (call, aid)
        for (i=0;i<COSIZE;i++) {
            if (centry.entries[i] == PRBADID) continue;
            if (centry.entries[i] == 0) break;
+#if defined(SUPERGROUPS)
+           if (aid < 0 && centry.entries[i] < 0) /* Supergroup */
+             code = RemoveFromSGEntry (tt, aid, centry.entries[i]);
+           else
+#endif
            code = RemoveFromEntry (tt, aid, centry.entries[i]);
            if (code) ABORT_WITH(tt,code);
            tentry.count--;             /* maintain count */
@@ -644,6 +703,54 @@ afs_int32 Delete (call, aid)
        nptr = tentry.next;
     }
 
+#if defined(SUPERGROUPS)
+    /* Delete each continuation block as a separate transaction
+     * so that no one transaction become too large to complete. */
+    {
+       struct prentryg *tentryg = (struct prentryg *)&tentry;
+       nptr = tentryg->nextsg;
+       while (nptr != NULL) {
+           struct contentry centry;
+           int i;
+
+           code = pr_ReadCoEntry(tt, 0, nptr, &centry);
+           if (code != 0) ABORT_WITH(tt,PRDBFAIL);
+           for (i=0;i<COSIZE;i++) {
+               if (centry.entries[i] == PRBADID) continue;
+               if (centry.entries[i] == 0) break;
+               code = RemoveFromEntry (tt, aid, centry.entries[i]);
+               if (code) ABORT_WITH(tt,code);
+               tentryg->countsg--;      /* maintain count */
+               if ((i&3) == 0) IOMGR_Poll();
+           }
+           tentryg->nextsg = centry.next;  /* thread out this block */
+           code = FreeBlock (tt, nptr);    /* free continuation block */
+           if (code) ABORT_WITH(tt,code);
+           code = pr_WriteEntry (tt, 0, loc, &tentry); /* update main entry */
+           if (code) ABORT_WITH(tt,code);
+
+           /* end this trans and start a new one */
+           code = ubik_EndTrans(tt);
+           if (code) return code;
+           IOMGR_Poll();          /* just to keep the connection alive */
+
+           code = ubik_BeginTrans(dbase,UBIK_WRITETRANS,&tt);
+           if (code) return code;
+           code = ubik_SetLock(tt,1,1,LOCKWRITE);
+           if (code) ABORT_WITH(tt,code);
+
+           /* re-read entry to get consistent uptodate info */
+           loc = FindByID (tt, aid);
+           if (loc == 0) ABORT_WITH(tt,PRNOENT);
+           code = pr_ReadEntry (tt, 0, loc, &tentry);
+           if (code) ABORT_WITH(tt,PRDBFAIL);
+
+           nptr = tentryg->nextsg;
+       }
+    }
+
+#endif /* SUPERGROUPS */
+
     /* Then move the owned chain, except possibly ourself to the orphan list.
      * Because this list can be very long and so exceed the size of a ubik
      * transaction, we start a new transaction every 50 entries. */
@@ -805,11 +912,20 @@ afs_int32 gid;
     code = pr_ReadEntry(tt,0,tempg,&gentry);
     if (code != 0) ABORT_WITH(tt,code);
     if (!(gentry.flags & PRGRP)) ABORT_WITH(tt,PRNOTGROUP);
+#if !defined(SUPERGROUPS)
     if (uentry.flags & PRGRP) ABORT_WITH(tt,PRNOTUSER);
+#endif
     if (!AccessOK (tt, cid, &gentry, PRP_REMOVE_MEM, 0)) ABORT_WITH(tt,PRPERM);
     code = RemoveFromEntry(tt,aid,gid);
     if (code != PRSUCCESS) ABORT_WITH(tt,code);
+#if defined(SUPERGROUPS)
+    if (!(uentry.flags & PRGRP))
+#endif
     code = RemoveFromEntry(tt,gid,aid);
+#if defined(SUPERGROUPS)
+    else
+       code = RemoveFromSGEntry(tt,gid,aid);
+#endif
     if (code != PRSUCCESS) ABORT_WITH(tt,code);
 
     code = ubik_EndTrans(tt);
@@ -1501,6 +1617,65 @@ afs_int32 listElements (call, aid, alist, over)
     return code;
 }
 
+#if defined(SUPERGROUPS)
+
+afs_int32 SPR_ListSuperGroups (call, aid, alist, over)
+  struct rx_call *call;
+  afs_int32 aid;
+  prlist *alist; 
+  afs_int32 *over;
+{ 
+  afs_int32 code;
+
+  code = listSuperGroups (call, aid, alist, over);
+  osi_auditU (call, "PTS_LstSGrps", code, AUD_LONG, aid, AUD_END);
+  return code;
+} 
+  
+afs_int32 listSuperGroups (call, aid, alist, over)
+  struct rx_call *call;
+  afs_int32 aid;
+  prlist *alist; 
+  afs_int32 *over;
+{ 
+    register afs_int32 code;
+    struct ubik_trans *tt;
+    afs_int32 cid;
+    afs_int32 temp;
+    struct prentry tentry;
+
+    alist->prlist_len = 0;
+    alist->prlist_val = (afs_int32 *) 0;
+
+    code = Initdb();
+    if (code != PRSUCCESS) goto done;
+    code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS,&tt);
+    if (code) goto done;
+    code = ubik_SetLock(tt,1,1,LOCKREAD);
+    if (code) ABORT_WITH(tt,code);
+    code = WhoIsThis(call,tt,&cid);
+    if (code) ABORT_WITH(tt,PRPERM);
+
+    temp = FindByID(tt,aid);
+    if (!temp) ABORT_WITH(tt,PRNOENT);
+    code = pr_ReadEntry (tt, 0, temp, &tentry);
+    if (code) ABORT_WITH(tt,code);
+    if (!AccessOK (tt, cid, &tentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
+       ABORT_WITH(tt,PRPERM);
+
+    code = GetSGList (tt, &tentry, alist);
+    *over = 0;
+    if (code == PRTOOMANY) *over = 1;
+    else if (code != PRSUCCESS) ABORT_WITH(tt,code);
+
+    code = ubik_EndTrans(tt);
+
+done:
+    return code;
+}
+
+#endif /* SUPERGROUPS */
+
 /* 
  * SPR_ListOwned
  * List the entries owned by this id.  If the id is zero,
@@ -1628,7 +1803,11 @@ afs_int32 *flag;
        if (code) ABORT_WITH(tt,code);
        code = pr_ReadEntry (tt, 0, gloc, &gentry);
        if (code) ABORT_WITH(tt,code);
+#if !defined(SUPERGROUPS)
        if ((uentry.flags & PRGRP) || !(gentry.flags & PRGRP)) ABORT_WITH(tt,PRBADARG);
+#else
+       if (!(gentry.flags & PRGRP)) ABORT_WITH(tt,PRBADARG);
+#endif
        if (!AccessOK (tt, cid, &uentry, 0, PRP_MEMBER_ANY) &&
            !AccessOK (tt, cid, &gentry, PRP_MEMBER_MEM, PRP_MEMBER_ANY))
            ABORT_WITH(tt,PRPERM);
index 8ef3fe2..18e5e23 100644 (file)
@@ -7,6 +7,18 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+/*
+ *                      (3) add new pts commands:
+ *
+ *                          Interactive - allow the pts command
+ *                                        to be run interactively.
+ *                          Quit        - quit interactive mode.
+ *                          Source      - allow input to come from a file(s).
+ *                          Sleep       - pause for a specified number
+ *                                        of seconds.
+ *
+ */
+
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -39,6 +51,93 @@ RCSID("$Header$");
 char *whoami;
 int force = 0;
 
+#if defined(SUPERGROUPS)
+
+/*
+ *  Add new pts commands:
+ *
+ *      Interactive - allow the pts command to be run interactively.
+ *      Quit        - quit interactive mode.
+ *      Source      - allow input to come from a file(s).
+ *      Sleep       - pause for a specified number of seconds.
+ */
+
+static int finished;
+static FILE *source;
+extern struct ubik_client *pruclient;
+
+struct sourcestack {
+        struct sourcestack *s_next;
+        FILE *s_file;
+} *shead;
+
+int Interactive (as)
+  register struct cmd_syndesc *as;
+{ 
+    finished = 0;
+    return 0;
+}   
+
+int Quit (as)
+  register struct cmd_syndesc *as;
+{ 
+    finished = 1;
+    return 0;
+}   
+
+int Source (as)
+  register struct cmd_syndesc *as;
+{
+    FILE *fd;
+    struct sourcestack *sp;
+
+    finished = 0;
+    if (!as->parms[0].items) {
+/* can this happen? */
+        return 1;
+    }
+    fd = fopen(as->parms[0].items->data, "r");
+    if (!fd) {
+perror(as->parms[0].items->data);
+        return errno;
+    }
+    sp = (struct sourcestack *) malloc(sizeof *sp);
+    if (!sp) {
+        return errno ? errno : ENOMEM;
+    } else {
+        sp->s_next = shead;
+        sp->s_file = source;
+        shead = sp;
+        source = fd;
+    }
+    return 0;
+}
+
+int Sleep (as)
+  register struct cmd_syndesc *as;
+{
+    int delay;
+    if (!as->parms[0].items) {
+/* can this happen? */
+        return 1;
+    }
+    delay = atoi(as->parms[0].items->data);
+    IOMGR_Sleep(delay);
+}
+
+int
+popsource()
+{
+    register  struct sourcestack *sp;
+    if (!(sp = shead)) return 0;
+    if (source != stdin) fclose(source);
+    source = sp->s_file;
+    shead = sp->s_next;
+    free((char*) sp);
+    return 1;
+}
+
+#endif /* SUPERGROUPS */
 
 int osi_audit()
 {
@@ -83,10 +182,19 @@ int GetGlobals (as)
 int CleanUp (as)
   register struct cmd_syndesc *as;
 {
+#if defined(SUPERGROUPS)
+    if (as && !strcmp(as->name,"help")) return;
+    if (pruclient) {
+    /* Need to shutdown the ubik_client & other connections */
+        pr_End();
+        rx_Finalize();
+    }
+#else
     if (!strcmp(as->name,"help")) return;
     /* Need to shutdown the ubik_client & other connections */
     pr_End();
     rx_Finalize();
+#endif /* SUPERGROUPS */
 
     return 0;
 }
@@ -120,6 +228,12 @@ CreateGroup (as)
                         "because group id %d was not negative", id);
                return code;
            }
+#if defined(SUPERGROUPS)
+           if (id == 0) {
+               printf ("0 isn't a valid user id; aborting\n");
+               return EINVAL;
+           }
+#endif
            idi = idi->next;
        } else id = 0;
 
@@ -833,6 +947,13 @@ int main (argc, argv)
 {
     register afs_int32 code;
     register struct cmd_syndesc *ts;
+#if defined(SUPERGROUPS)
+    char line[2048];
+    char *cp, *lastp;
+    int parsec; 
+    char *parsev[CMD_MAXPARMS];
+    char *savec;
+#endif
 #ifdef WIN32
     WSADATA WSAjunk;
 #endif
@@ -940,9 +1061,73 @@ int main (argc, argv)
     cmd_AddParm(ts, "-groups", CMD_FLAG, CMD_OPTIONAL, "list group entries");
     add_std_args (ts);
     
+#if defined(SUPERGROUPS)
+
+    ts = cmd_CreateSyntax("interactive",Interactive,0,
+           "enter interactive mode");
+    add_std_args (ts);
+    cmd_CreateAlias (ts, "in");
+
+    ts = cmd_CreateSyntax("quit",Quit,0,
+           "exit program");
+    add_std_args (ts);
+
+    ts = cmd_CreateSyntax("source",Source,0,
+           "read commands from file");
+    cmd_AddParm(ts,"-file",CMD_SINGLE,0,"filename");
+    add_std_args (ts);
+
+    ts = cmd_CreateSyntax("sleep",Sleep,0,
+           "pause for a bit");
+    cmd_AddParm(ts,"-delay",CMD_SINGLE,0,"seconds");
+    add_std_args (ts);
+
+#endif /* SUPERGROUPS */
+
     cmd_SetBeforeProc(GetGlobals,0);
+
+#if defined(SUPERGROUPS)
+    finished = 1;
+    if (code = cmd_Dispatch(argc,argv)) {
+       CleanUp(0);
+       exit(1);
+    }
+    source = stdin;
+    while (!finished) {
+       if (isatty(fileno(source)))
+           fprintf(stderr,"pts> ");
+       if (!fgets(line, sizeof line, source)) {
+           if (!popsource()) break;
+           continue;
+       }
+       lastp = 0;
+       for (cp = line; *cp; ++cp)
+           if (!isspace(*cp))
+               lastp = 0;
+           else if (!lastp)
+               lastp = cp;
+       if (lastp) *lastp = 0; 
+       if (!*line) continue;
+       code = cmd_ParseLine(line, parsev, &parsec,
+                            sizeof(parsev)/sizeof(*parsev));
+       if (code) {
+           com_err(whoami, code, "parsing line: <%s>", line);
+           exit(2);
+       }
+       savec = parsev[0];
+       parsev[0] = argv[0];
+       code = cmd_Dispatch(parsec, parsev);
+       parsev[0] = savec;
+       cmd_FreeArgv(parsev);
+    }
+    CleanUp(0);
+    exit(0);
+
+#else  /* SUPERGROUPS */
+
     cmd_SetAfterProc(CleanUp,0);
     code = cmd_Dispatch(argc,argv);
     exit (code != 0);
+#endif /* SUPERGROUPS */
 }
 
index 9047d2b..8ab574a 100644 (file)
@@ -7,6 +7,107 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+/*
+ *                      A general description of the supergroup changes
+ *                      to ptserver:
+ *
+ *                      In AFS users can be members of groups. When you add
+ *                      a user, u1, to a group, g1, you add the user id for u1
+ *                      to an entries list in g1. This is a list of all the
+ *                      members of g1.
+ *                      You also add the id for g1 to an entries list in u1.
+ *                      This is a list of all the groups this user is a
+ *                      member of.
+ *                      The list has room for 10 entries. If more are required,
+ *                      a continuation record is created.
+ *
+ *                      With UMICH mods, u1 can be a group. When u1 is a group
+ *                      a new field is required to list the groups this group
+ *                      is a member of (since the entries field is used to
+ *                      list it's members). This new field is supergroups and
+ *                      has two entries. If more are required, a continuation
+ *                      record is formed. 
+ *                      There are two additional fields required, nextsg is
+ *                      an address of the next continuation record for this
+ *                      group, and countsg is the count for the number of 
+ *                      groups this group is a member of.
+ *                   
+ *
+ *
+ *      09/18/95 jjm    Add mdw's changes to afs-3.3a Changes:
+ *                      (1) Add the parameter -groupdepth or -depth to
+ *                          define the maximum search depth for supergroups.
+ *                          Define the variable depthsg to be the value of
+ *                          the parameter. The default value is set to 5.
+ *
+ *                      (3) Make sure the sizes of the struct prentry and
+ *                          struct prentryg are equal. If they aren't equal
+ *                          the pt database will be corrupted.
+ *                          The error is reported with an fprintf statement,
+ *                          but this doesn't print when ptserver is started by
+ *                          bos, so all you see is an error message in the
+ *                          /usr/afs/logs/BosLog file. If you start the
+ *                          ptserver without bos the fprintf will print
+ *                          on stdout.
+ *                          The program will terminate with a PT_EXIT(1).
+ *
+ *
+ *                      Transarc does not currently use opcodes past 520, but
+ *                      they *could* decide at any time to use more opcodes.
+ *                      If they did, then one part of our local mods,
+ *                      ListSupergroups, would break.  I've therefore
+ *                      renumbered it to 530, and put logic in to enable the
+ *                      old opcode to work (for now).
+ *
+ *      2/1/98 jjm      Add mdw's changes for bit mapping for supergroups
+ *                      Overview:
+ *                      Before fetching a supergroup, this version of ptserver
+ *                      checks to see if it was marked "found" and "not a
+ *                      member".  If and only if so, it doesn't fetch the group.
+ *                      Since this should be the case with most groups, this
+ *                      should save a significant amount of CPU in redundant
+ *                      fetches of the same group.  After fetching the group,
+ *                      it sets "found", and either sets or clears "not a
+ *                      member", depending on if the group was a member of
+ *                      other groups.  When it writes group entries to the
+ *                      database, it clears the "found" flag.
+ */
+
+#if defined(SUPERGROUPS)
+/*
+ *  A general description of the supergroup changes
+ *  to ptserver:
+ *
+ *  In AFS users can be members of groups. When you add a user, u1,
+ *  to a group, g1, you add the user id for u1 to an entries list
+ *  in g1. This is a list of all the members of g1.  You also add
+ *  the id for g1 to an entries list in u1.  This is a list of all
+ *  the groups this user is a member of.  The list has room for 10
+ *  entries. If more are required, a continuation record is created.
+ *
+ *  With UMICH mods, u1 can be a group. When u1 is a group a new
+ *  field is required to list the groups this group is a member of
+ *  (since the entries field is used to list it's members). This
+ *  new field is supergroups and has two entries. If more are
+ *  required, a continuation record is formed.
+ *
+ *  There are two additional fields required, nextsg is an address
+ *  of the next continuation record for this group, and countsg is
+ *  the count for the number of groups this group is a member of.
+ *
+ *  Bit mapping support for supergroups:
+ *
+ *  Before fetching a supergroup, this version of ptserver checks to
+ *  see if it was marked "found" and "not a member".  If and only if
+ *  so, it doesn't fetch the group.  Since this should be the case
+ *  with most groups, this should save a significant amount of CPU in
+ *  redundant fetches of the same group.  After fetching the group, it
+ *  sets "found", and either sets or clears "not a member", depending
+ *  on if the group was a member of other groups.  When it writes
+ *  group entries to the database, it clears the "found" flag.
+ */
+#endif
+
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -51,6 +152,10 @@ struct prheader cheader;
 struct ubik_dbase *dbase;
 struct afsconf_dir *prdir;
 
+#if defined(SUPERGROUPS)
+extern afs_int32 depthsg;
+#endif
+
 extern afs_int32 ubik_lastYesTime;
 extern afs_int32 ubik_nBuffers;
 
@@ -123,6 +228,21 @@ void main (argc, argv)
 
     pr_dbaseName = AFSDIR_SERVER_PRDB_FILEPATH;
 
+#if defined(SUPERGROUPS)
+    /* make sure the structures for database records are the same size */
+    if((sizeof(struct prentry) != ENTRYSIZE) ||
+        (sizeof(struct prentryg) != ENTRYSIZE)) {
+      fprintf(stderr,"The structures for the database records are different"
+                    " sizes\n"
+                    "struct prentry = %d\n"
+                    "struct prentryg = %d\n"
+                    "ENTRYSIZE = %d\n",
+                     sizeof(struct prentry), sizeof(struct prentryg),
+                    ENTRYSIZE); 
+      PT_EXIT(1);
+    }
+#endif
+
     for (a=1; a<argc; a++) {
        int alen;
        lcstring (arg, argv[a], sizeof(arg));
@@ -144,6 +264,12 @@ void main (argc, argv)
           }
        }
        else if (strncmp (arg, "-rebuild", alen) == 0) /* rebuildDB++ */ ;
+#if defined(SUPERGROUPS)
+       else if ((strncmp (arg, "-groupdepth", alen) == 0) ||
+                (strncmp (arg, "-depth", alen) == 0)) {
+           depthsg = atoi(argv[++a]);  /* Max search depth for supergroups */
+       }
+#endif
        else if (strncmp (arg, "-enable_peer_stats", alen) == 0) {
            rx_enablePeerRPCStats();
        }
@@ -163,21 +289,42 @@ void main (argc, argv)
        else if (*arg == '-') {
                /* hack in help flag support */
 
+#if defined(SUPERGROUPS)
 #ifndef AFS_NT40_ENV
                printf ("Usage: ptserver [-database <db path>] "
                        "[-syslog[=FACILITY]] "
                        "[-p <number of processes>] [-rebuild] "
+                       "[-groupdepth <depth>] "
                        "[-enable_peer_stats] [-enable_process_stats] "
                        "[-help]\n");
+#else /* AFS_NT40_ENV */
+               printf ("Usage: ptserver [-database <db path>] "
+                       "[-p <number of processes>] [-rebuild] "
+                       "[-groupdepth <depth>] "
+                       "[-help]\n");
+#endif
 #else
+#ifndef AFS_NT40_ENV
                printf ("Usage: ptserver [-database <db path>] "
+                       "[-syslog[=FACILITY]] "
                        "[-p <number of processes>] [-rebuild] "
+                       "[-enable_peer_stats] [-enable_process_stats] "
                        "[-help]\n");
+#else /* AFS_NT40_ENV */
+               printf ("Usage: ptserver [-database <db path>] "
+                       "[-p <number of processes>] [-rebuild] "
+                       "[-help]\n");
+#endif
 #endif
                fflush(stdout);
 
            PT_EXIT(1);
        }
+#if defined(SUPERGROUPS)
+       else {
+           fprintf (stderr, "Unrecognized arg: '%s' ignored!\n", arg);
+       }
+#endif
     }
 
     OpenLog(AFSDIR_SERVER_PTLOG_FILEPATH);     /* set up logging */
@@ -258,6 +405,11 @@ void main (argc, argv)
        com_err (whoami, code, "Ubik init failed");
        PT_EXIT(2);
     }
+
+#if defined(SUPERGROUPS)
+    pt_hook_write();
+#endif
+
     sc[0] = rxnull_NewServerSecurityObject();
     sc[1] = 0;
     if (kerberosKeys) {
@@ -290,4 +442,5 @@ void main (argc, argv)
 
     rx_StartServer(1);
     osi_audit (PTS_FinishEvent, -1, AUD_END);
+    exit(0);
 }
index 4dc0387..e2cd41a 100644 (file)
@@ -125,6 +125,38 @@ struct prentry {
     char name[PR_MAXNAMELEN];          /* user or group name */
 };
 
+#if defined(SUPERGROUPS)
+
+struct prentryg {
+    afs_int32 flags;                   /* random flags */
+    afs_int32 id;                      /* user or group id */
+    afs_int32 cellid;                  /* reserved for cellID */
+    afs_int32 next;                    /* next block same entry (or freelist) */
+#ifdef PR_REMEMBER_TIMES
+    afs_uint32 createTime, addTime, removeTime, changeTime;
+    afs_int32 reserved[1];
+#else
+    afs_int32 reserved[5];
+#endif
+    afs_int32 entries[PRSIZE];         /* groups a user is a member of (or list of members */
+    afs_int32 nextID;                  /* id hash table next pointer */
+    afs_int32 nextName;                        /* name has table next ptr */
+    afs_int32 owner;                   /* id of owner of entry */
+    afs_int32 creator;                 /* may differ from owner */
+    afs_int32 ngroups;                 /* number of groups this user has created - 0 for group entries */
+    afs_int32 nusers;                  /* number of foreign user entries this user has created - 0 for group entries NYI */
+    afs_int32 count;                   /* number of members/groups for this group/user */
+    afs_int32 countsg;                 /* number of supergroups for this group */
+    afs_int32 owned;                   /* chain of groups owned by this entry */
+    afs_int32 nextOwned;               /* chain of groups for owner of this entry */
+    afs_int32 nextsg;                  /* next block same entry for supergroups */
+#define SGSIZE 2                       /* number of supergroup entries */
+    afs_int32 supergroup[SGSIZE];      /* supergroups this group belongs to */
+    char name[PR_MAXNAMELEN];          /* user or group name */
+};
+
+#endif /* SUPERGROUPS */
+
 struct contentry {                     /* continuation of entry */
     afs_int32 flags;               
     afs_int32 id;
index 45a88a2..ebff0bd 100644 (file)
@@ -150,6 +150,9 @@ afs_int32 pr_Initialize (secLevel, confDir, cell)
        /* If secLevel is two assume we're on a file server and use
          * ClientAuthSecure if possible. */
        code = afsconf_ClientAuthSecure (tdir, &sc[2], &scIndex);
+       if (code)
+           fprintf(stderr,"libprot: clientauthsecure returns %d %s"
+                   " (so trying noauth)\n",code, error_message(code));
        if (code) scIndex = 0;          /* use noauth */
        if (scIndex != 2)
            /* if there was a problem, an unauthenticated conn is returned */
index c742867..da2b599 100644 (file)
@@ -7,6 +7,19 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+/* 
+ *                      (5) Add functions to process supergroups:
+ *                          ChangeIDEntry(), RemoveFromSGEntry(),
+ *                          AddToSGEntry(), GetListSG2().
+ *                      (6) Add code to existing functions to process
+ *                          supergroups.
+ *      2/1/98 jjm      Add mdw's changes for bit mapping for supergroups
+ *
+ *     09/26/02 kwc    Move depthsg definition here from ptserver.c since
+ *                     pt_util needs it defined also, and this file is
+ *                     common between the two programs.
+ */
+
 #include <afsconfig.h>
 #include <afs/param.h>
 
@@ -48,6 +61,130 @@ extern int IDCmp();
 extern afs_int32 AddToEntry();
 static char *whoami = "ptserver";
 
+#if defined(SUPERGROUPS)
+
+#include "map.h"
+
+afs_int32 depthsg = 5;  /* Maximum iterations used during IsAMemberOF */
+extern int IDCmp();
+afs_int32 GetListSG2 (struct ubik_trans *at, afs_int32 gid, prlist *alist,
+       afs_int32 *sizeP, afs_int32 depth);
+
+struct map *sg_flagged;
+struct map *sg_found;
+
+#define NIL_MAP ((struct map *) 0)
+
+/* pt_mywrite hooks into the logic that writes ubik records to disk
+ *  at a very low level.  It invalidates mappings in sg_flagged/sg_found.
+ *  By hoooking in at this level, we ensure that a ubik file reload
+ *  invalidates our incore cache.
+ *
+ * We assert records, cheaders and everything else are 0 mod 64.
+ *  So, we can always see the first 64 bytes of any record written.
+ *  The stuff we're interested in (flags, id) are in the first 8 bytes.
+ *  so we can always tell if we're writing a group record.
+ */
+
+int (*pt_save_dbase_write)();
+
+int pt_mywrite(tdb, fno, bp, pos, count)
+       struct ubik_dbase *tdb;
+       afs_int32 fno, pos, count;
+       char *bp;
+{
+       afs_uint32 headersize = ntohl(cheader.headerSize);
+
+       if (fno == 0 && pos+count > headersize)
+       {
+               afs_int32 p, l, c, o;
+               char *cp;
+               p = pos-headersize;
+               cp = bp;
+               l = count;
+               if (p < 0) {
+                       l += p;
+                       p = 0;
+               }
+               while (l > 0)
+               {
+                       o = p%ENTRYSIZE;
+                       c = ENTRYSIZE-o;
+                       if (c > l)
+                               c = l;
+#if DEBUG_SG_MAP
+                       if (o)
+                               fprintf (stderr,"Writing %d bytes of entry @ %#lx(+%d)\n",
+                                       c, p-o, o);
+                       else if (c == ENTRYSIZE)
+                               fprintf (stderr,"Writing %d bytes of entry @ %#lx (%d<%s>,%d)\n",
+                                       c, p,
+                                       ((struct prentry *)cp)->flags,
+(((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" :
+"?",
+                                       ((struct prentry *)cp)->id);
+                       else if (c >= 8)
+                               fprintf (stderr,"Writing first %d bytes of entry @ %#lx (%d<%s>,%d)\n",
+                                       c, p,
+                                       ((struct prentry *)cp)->flags,
+(((struct prentry *)cp)->flags&PRTYPE)==PRUSER ? "user" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRFREE ? "free" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRGRP ? "group" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRCONT ? "cont" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRCELL ? "cell" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRFOREIGN ? "foreign" :
+(((struct prentry *)cp)->flags&PRTYPE)==PRINST ? "sub/super instance" :
+"?",
+                                       ((struct prentry *)cp)->id);
+                       else
+                               fprintf (stderr,"Writing %d bytes of entry @ %#lx\n",
+                                       c, p);
+#endif
+                       if (!o && c >= 8 &&
+                               (((struct prentry *)cp)->flags&PRTYPE)==PRGRP)
+                       {
+#if DEBUG_SG_MAP
+if (in_map(sg_found, -((struct prentry *)cp)->id))fprintf(stderr,"Unfound: Removing group %d\n",
+((struct prentry *)cp)->id);
+if (in_map(sg_flagged, -((struct prentry *)cp)->id))fprintf(stderr,"Unflag: Removing group %d\n",
+((struct prentry *)cp)->id);
+#endif
+                               sg_found = bic_map(sg_found, add_map(NIL_MAP,
+                                       -((struct prentry *)cp)->id));
+                               sg_flagged = bic_map(sg_flagged, add_map(NIL_MAP,
+                                       -((struct prentry *)cp)->id));
+                       }
+                       cp += c;
+                       p += c;
+                       l -= c;
+               }
+       }
+       return (*pt_save_dbase_write)(tdb, fno, bp, pos, count);
+}
+
+/*
+ * this function attaches pt_mywrite.  It's called once,
+ *  just after ubik_ServerInit.
+ */
+
+pt_hook_write()
+{
+       extern struct ubik_dbase *ubik_dbase;
+       if (ubik_dbase->write != pt_mywrite)
+       {
+               pt_save_dbase_write = ubik_dbase->write;
+               ubik_dbase->write = pt_mywrite;
+       }
+}
+
+#endif /* SUPERGROUPS */
+
 /* CorrectUserName - Check to make sure a user name is OK.  It must not include
  *   either a colon (or it would look like a group) or an atsign (or it would
  *   look like a foreign user).  The length is checked as well to make sure
@@ -501,6 +638,163 @@ afs_int32 RemoveFromEntry (at, aid, bid)
     return PRNOENT;
 }
 
+#if defined(SUPERGROUPS)
+/* ChangeIDEntry - remove aid from bid's entries list, freeing a continuation
+ * entry if appropriate */
+
+afs_int32 ChangeIDEntry (at, aid, newid, bid)
+  register struct ubik_trans *at;
+  register afs_int32 aid;
+  register afs_int32 bid;
+  afs_int32 newid;
+{
+    register afs_int32 code;
+    struct prentry tentry;
+    struct contentry centry;
+    afs_int32 temp;
+    afs_int32 i,j;
+    afs_int32 nptr;
+
+    if (aid == bid) return PRINCONSISTENT;
+    temp = FindByID(at,bid);
+    if (temp == 0) {
+        return PRNOENT;
+    }
+    code = pr_ReadEntry(at, 0, temp, &tentry);
+    if (code != 0) return code;
+    for (i=0;i<PRSIZE;i++) {
+        if (tentry.entries[i] == aid) {
+            tentry.entries[i] = newid;
+            code = pr_WriteEntry(at,0,temp,&tentry);
+            if (code != 0) return code;
+            return PRSUCCESS;
+        }
+        if (tentry.entries[i] == 0) {   /* found end of list */
+            return PRNOENT;
+        }
+    }
+
+    nptr = tentry.next;
+    while (nptr != NULL) {
+        code = pr_ReadCoEntry(at,0,nptr,&centry);
+        if (code != 0) return code;
+        if ((centry.id != bid) || !(centry.flags & PRCONT)) {
+fprintf(stderr,"ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
+bid, centry.id, centry.flags); 
+            return PRDBBAD;
+        }
+        for (i=0;i<COSIZE;i++) {
+            if (centry.entries[i] == aid) {
+                centry.entries[i] = newid;
+                for (j=0;j<COSIZE;j++)
+                    if (centry.entries[j] != PRBADID &&
+                        centry.entries[j] != 0) break;
+                code = pr_WriteCoEntry(at,0,nptr,&centry);
+                if (code != 0) return code;
+                return 0;
+            }
+            if (centry.entries[i] == 0) {
+                return PRNOENT;
+            }
+        } /* for all coentry slots */
+        nptr = centry.next;
+    } /* while there are coentries */
+    return PRNOENT;
+}
+
+/*  #ifdef SUPERGROUPS */
+/* RemoveFromSGEntry - remove aid from bid's supergroups list, freeing a
+ * continuation entry if appropriate */
+
+afs_int32 RemoveFromSGEntry (at, aid, bid)
+  register struct ubik_trans *at;
+  register afs_int32 aid;
+  register afs_int32 bid;
+{
+    register afs_int32 code;
+    struct prentry tentry;
+    struct prentryg *tentryg;
+    struct contentry centry;
+    struct contentry hentry;
+    afs_int32 temp;
+    afs_int32 i,j;
+    afs_int32 nptr;
+    afs_int32 hloc;
+
+    if (aid == bid) return PRINCONSISTENT;
+    memset(&hentry, 0, sizeof(hentry));
+    temp = FindByID(at,bid);
+    if (temp == 0) {
+        return PRNOENT;
+    }
+    code = pr_ReadEntry(at, 0, temp, &tentry);
+    if (code != 0) return code;
+#ifdef PR_REMEMBER_TIMES
+    tentry.removeTime = time((afs_int32*)0);
+#endif
+    tentryg = (struct prentryg *)&tentry;
+    for (i=0;i<SGSIZE;i++) {
+        if (tentryg->supergroup[i] == aid) {
+            tentryg->supergroup[i] = PRBADID;
+            tentryg->countsg--;
+            code = pr_WriteEntry(at,0,temp,&tentry);
+            if (code != 0) return code;
+            return PRSUCCESS;
+        }
+        if (tentryg->supergroup[i] == 0) {   /* found end of list */
+            return PRNOENT;
+        }
+    }
+    hloc = 0;
+    nptr = tentryg->nextsg;
+    while (nptr != NULL) {
+        code = pr_ReadCoEntry(at,0,nptr,&centry);
+        if (code != 0) return code;
+        if ((centry.id != bid) || !(centry.flags & PRCONT)) {
+           fprintf(stderr,"ChangeIDEntry: bad database bid=%d centry.id=%d .flags=%d\n",
+               bid, centry.id, centry.flags);
+            return PRDBBAD;
+        }
+        for (i=0;i<COSIZE;i++) {
+            if (centry.entries[i] == aid) {
+                centry.entries[i] = PRBADID;
+                for (j=0;j<COSIZE;j++)
+                    if (centry.entries[j] != PRBADID &&
+                        centry.entries[j] != 0) break;
+                if (j == COSIZE) {   /* can free this block */
+                    if (hloc == 0) {
+                        tentryg->nextsg = centry.next;
+                    }
+                    else {
+                        hentry.next = centry.next;
+                        code = pr_WriteCoEntry (at, 0, hloc, &hentry);
+                        if (code != 0) return code;
+                    }
+                    code = FreeBlock (at, nptr);
+                    if (code) return code;
+                }
+                else { /* can't free it yet */
+                    code = pr_WriteCoEntry(at,0,nptr,&centry);
+                    if (code != 0) return code;
+                }
+                tentryg->countsg--;
+                code = pr_WriteEntry(at,0,temp,&tentry);
+                if (code) return PRDBFAIL;
+                return 0;
+            }
+            if (centry.entries[i] == 0) {
+                return PRNOENT;
+            }
+        } /* for all coentry slots */
+        hloc = nptr;
+        nptr = centry.next;
+        bcopy((char*)&centry,(char*)&hentry,sizeof(centry));
+    } /* while there are coentries */
+    return PRNOENT;
+}
+
+#endif /* SUPERGROUPS */
+
 /* DeleteEntry - delete the entry in tentry at loc, removing it from all
  * groups, putting groups owned by it on orphan chain, and freeing the space */
 
@@ -539,9 +833,27 @@ afs_int32 DeleteEntry (at, tentry, loc)
     for (i=0;i<PRSIZE;i++) {
        if (tentry->entries[i] == PRBADID) continue;
        if (tentry->entries[i] == 0) break;
+#if defined(SUPERGROUPS)
+       if ((tentry->flags & PRGRP) && tentry->entries[i] < 0) /* Supergroup */
+         code = RemoveFromSGEntry (at, tentry->id, tentry->entries[i]);
+       else
+#endif
        code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
        if (code) return code;
     }
+#if defined(SUPERGROUPS)
+    {
+       struct prentryg *tentryg = (struct prentryg *)tentry;
+
+       /* Then remove the entire supergroup list */
+       for (i=0;i<SGSIZE;i++) {
+           if (tentryg->supergroup[i] == PRBADID) continue;
+           if (tentryg->supergroup[i] == 0) break; 
+           code = RemoveFromEntry (at, tentry->id, tentryg->supergroup[i]);
+           if (code) return code;
+       }
+    }
+#endif /* SUPERGROUPS */
     nptr = tentry->next;
     while (nptr != (afs_int32)NULL) {
        code = pr_ReadCoEntry(at,0,nptr,&centry);
@@ -721,6 +1033,119 @@ afs_int32 AddToEntry (tt, entry, loc, aid)
        
 }
 
+#if defined(SUPERGROUPS)
+
+/* AddToSGEntry - add aid to entry's supergroup list, alloc'ing a
+ * continuation block if needed.
+ *
+ * Note the entry is written out by this routine. */
+afs_int32 AddToSGEntry (tt, entry, loc, aid)
+  struct ubik_trans *tt;
+  struct prentry *entry;
+  afs_int32 loc;
+  afs_int32 aid;
+{ 
+    register afs_int32 code;
+    afs_int32 i; 
+    struct contentry nentry;
+    struct contentry aentry;
+    struct prentryg *entryg;
+    afs_int32 nptr;
+    afs_int32 last;                          /* addr of last cont. block */
+    afs_int32 first = 0;
+    afs_int32 cloc;
+    afs_int32 slot = -1;
+
+    if (entry->id == aid) return PRINCONSISTENT;
+#ifdef PR_REMEMBER_TIMES
+    entry->addTime = time((afs_int32*)0);
+#endif
+    entryg = (struct prentryg *)entry;
+    for (i=0;i<SGSIZE;i++) {
+       if (entryg->supergroup[i] == aid)
+           return PRIDEXIST;
+       if (entryg->supergroup[i] == PRBADID) { /* remember this spot */
+           first = 1;
+           slot = i;
+       }
+       else if (entryg->supergroup[i] == 0) { /* end of the line */
+           if (slot == -1) {
+               first = 1;
+               slot = i;
+           }
+           break;
+       }
+    }
+    last = 0;
+    nptr = entryg->nextsg;
+    while (nptr != NULL) {
+       code = pr_ReadCoEntry(tt,0,nptr,&nentry);
+       if (code != 0) return code;
+       last = nptr;
+       if (!(nentry.flags & PRCONT)) return PRDBFAIL;
+       for (i=0;i<COSIZE;i++) {
+           if (nentry.entries[i] == aid)
+               return PRIDEXIST;
+           if (nentry.entries[i] == PRBADID) {
+               if (slot == -1) {
+                   slot = i;
+                   cloc = nptr;
+               }
+           }
+           else if (nentry.entries[i] == 0) {
+               if (slot == -1) {
+                   slot = i;
+                   cloc = nptr;
+               }
+               break;
+           }
+       }
+       nptr = nentry.next;
+    }
+    if (slot != -1) {                   /* we found a place */
+       entryg->countsg++;
+       if (first) {  /* place is in first block */
+           entryg->supergroup[slot] = aid;
+           code = pr_WriteEntry (tt, 0, loc, entry);
+           if (code != 0) return code;
+           return PRSUCCESS;
+       }
+       code = pr_WriteEntry (tt, 0, loc, entry);
+       if (code) return code;
+       code = pr_ReadCoEntry(tt,0,cloc,&aentry);
+       if (code != 0) return code;
+       aentry.entries[slot] = aid;
+       code = pr_WriteCoEntry(tt,0,cloc,&aentry);
+       if (code != 0) return code;
+       return PRSUCCESS;
+    }
+    /* have to allocate a continuation block if we got here */
+    nptr = AllocBlock(tt);
+    if (last) {
+       /* then we should tack new block after last block in cont. chain */
+       nentry.next = nptr;
+       code = pr_WriteCoEntry(tt,0,last,&nentry);
+       if (code != 0) return code;
+    }
+    else {
+       entryg->nextsg = nptr;
+    }
+    memset(&aentry, 0, sizeof(aentry));
+    aentry.flags |= PRCONT;
+    aentry.id = entry->id;
+    aentry.next = NULL;
+    aentry.entries[0] = aid;
+    code = pr_WriteCoEntry(tt,0,nptr,&aentry);
+    if (code != 0) return code;
+    /* don't forget to update count, here! */ 
+    entryg->countsg++;
+    code = pr_WriteEntry (tt, 0, loc, entry);
+    return code;
+
+}
+#endif /* SUPERGROUPS */
+
 afs_int32 AddToPRList (alist, sizeP, id)
   prlist *alist;
   int *sizeP;
@@ -766,6 +1191,11 @@ afs_int32 GetList (at, tentry, alist, add)
        if (tentry->entries[i] == 0) break;
        code = AddToPRList (alist, &size, tentry->entries[i]);
        if (code) return code;
+#if defined(SUPERGROUPS)
+       if (!add) continue;
+       code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg);
+       if (code) return code;
+#endif
     }
 
     for (nptr = tentry->next; nptr != 0; nptr = centry.next) {
@@ -777,6 +1207,11 @@ afs_int32 GetList (at, tentry, alist, add)
            if (centry.entries[i] == 0) break;
            code = AddToPRList (alist, &size, centry.entries[i]);
            if (code) return code;
+#if defined(SUPERGROUPS)
+           if (!add) continue;
+           code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg);
+           if (code) return code;
+#endif
        }
        if (count++ > 50) IOMGR_Poll(), count = 0;
     }
@@ -820,6 +1255,11 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
        if (tentry->entries[i] == 0) break;
        code = AddToPRList (alist, &size, tentry->entries[i]);
        if (code) return code;
+#if defined(SUPERGROUPS)
+       if (!add) continue;
+       code = GetListSG2 (at, tentry->entries[i], alist, &size, depthsg);
+       if (code) return code;
+#endif
     }
 
     nptr = tentry->next;
@@ -832,6 +1272,11 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
            if (centry.entries[i] == 0) break;
            code = AddToPRList (alist, &size, centry.entries[i]);
            if (code) return code;
+#if defined(SUPERGROUPS)
+           if (!add) continue;
+           code = GetListSG2 (at, centry.entries[i], alist, &size, depthsg);
+           if (code) return code;
+#endif
        }
        nptr = centry.next;
        if (count++ > 50) IOMGR_Poll(), count = 0;
@@ -876,6 +1321,158 @@ afs_int32 GetList2 (at, tentry, tentry2 , alist, add)
     return PRSUCCESS;
 }
 
+#if defined(SUPERGROUPS)
+
+afs_int32 GetListSG2 (at, gid, alist, sizeP, depth)
+    struct ubik_trans *at;
+    afs_int32 gid;
+    prlist *alist;
+    afs_int32 depth;
+    afs_int32 *sizeP;
+{
+    register afs_int32 code;
+    struct prentry tentry;
+    struct prentryg *tentryg = (struct prentryg *)&tentry;
+    afs_int32 i;
+    struct contentry centry;
+    afs_int32 nptr;
+    int count = 0;
+    afs_int32 temp;
+    int didsomething;
+#if DEBUG_SG_MAP
+    int predictfound, predictflagged;
+#endif
+
+#if DEBUG_SG_MAP
+    predictfound = 0;
+    if (!in_map(sg_flagged, -gid))
+    {
+       predictflagged = 0;
+       fprintf(stderr,"GetListSG2: I have not yet searched for gid=%d\n", gid);
+    }
+    else if (predictflagged = 1, in_map(sg_found, -gid)) {
+       predictfound = 1;
+       fprintf (stderr,
+               "GetListSG2: I have already searched for gid=%d, and predict success.\n",
+               gid);
+    }
+#endif
+
+    if (in_map(sg_flagged, -gid) && !in_map(sg_found, -gid)) {
+#if DEBUG_SG_MAP
+       fprintf (stderr,
+               "GetListSG2: I have already searched for gid=%d, and predict failure.\n",
+               gid);
+#else
+        return 0;
+#endif
+    }
+
+    if (depth < 1) return 0;
+    temp = FindByID (at, gid);
+    if (!temp) {
+        code = PRNOENT;
+        return code;
+    }
+    code = pr_ReadEntry (at, 0, temp, &tentry);
+    if (code) return code;
+#if DEBUG_SG_MAP
+    fprintf (stderr,"GetListSG2: lookup for gid=%d [\n", gid);
+#endif
+    didsomething = 0;
+
+    for (i=0;i<SGSIZE;i++) {
+        if (tentryg->supergroup[i] == PRBADID) continue;
+        if (tentryg->supergroup[i] == 0) break;
+        didsomething = 1;
+#if DEBUG_SG_MAP
+       fprintf (stderr,"via gid=%d, added %d\n", gid, e.tentryg.supergroup[i]);
+#endif
+        code = AddToPRList (alist, sizeP, tentryg->supergroup[i]);
+        if (code) return code;
+        code = GetListSG2 (at, tentryg->supergroup[i], alist, sizeP, depth-1);
+        if (code) return code;
+    }
+
+    nptr = tentryg->nextsg;
+    while (nptr != NULL) {
+        didsomething = 1;
+        /* look through cont entries */
+        code = pr_ReadCoEntry(at,0,nptr,&centry);
+        if (code != 0) return code;
+        for (i=0;i<COSIZE;i++) {
+            if (centry.entries[i] == PRBADID) continue;
+            if (centry.entries[i] == 0) break;
+#if DEBUG_SG_MAP
+           fprintf (stderr,"via gid=%d, added %d\n", gid, e.centry.entries[i]);
+#endif
+            code = AddToPRList (alist, sizeP, centry.entries[i]);
+            if (code) return code;
+            code = GetListSG2 (at, centry.entries[i], alist, sizeP, depth-1);
+            if (code) return code;
+        }
+        nptr = centry.next;
+        if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+#if DEBUG_SG_MAP
+    fprintf (stderr,"] for gid %d, done [flag=%s]\n", gid, didsomething ? "TRUE" : "FALSE");
+    if (predictflagged && didsomething != predictfound)
+    fprintf (stderr,"**** for gid=%d, didsomething=%d predictfound=%d\n",
+               didsomething, predictfound);
+#endif
+    if (didsomething)
+        sg_found = add_map(sg_found, -gid);
+        else sg_found = bic_map(sg_found, add_map(NIL_MAP, -gid));
+    sg_flagged = add_map(sg_flagged, -gid);
+    return 0;
+}
+
+afs_int32 GetSGList (at, tentry, alist)
+    struct ubik_trans *at;
+    struct prentry *tentry;
+    prlist *alist;
+{
+    register afs_int32 code;
+    afs_int32 i;
+    struct contentry centry;
+    struct prentryg *tentryg;
+    afs_int32 nptr;
+    int size;
+    int count = 0;
+
+    size = 0;
+    alist->prlist_val = 0;
+    alist->prlist_len = 0;
+
+    tentryg = (struct prentryg *)tentry;
+    for (i=0;i<SGSIZE;i++) {
+        if (tentryg->supergroup[i] == PRBADID) continue;
+        if (tentryg->supergroup[i] == 0) break;
+        code = AddToPRList (alist, &size, tentryg->supergroup[i]);
+        if (code) return code; 
+    }
+
+    nptr = tentryg->nextsg;
+    while (nptr != NULL) {
+        /* look through cont entries */
+        code = pr_ReadCoEntry(at,0,nptr,&centry);
+        if (code != 0) return code;
+        for (i=0;i<COSIZE;i++) {
+            if (centry.entries[i] == PRBADID) continue;
+            if (centry.entries[i] == 0) break;
+            code = AddToPRList (alist, &size, centry.entries[i]);
+            if (code) return code;
+        }
+        nptr = centry.next;
+        if (count++ > 50) IOMGR_Poll(), count = 0;
+    }
+
+    if (alist->prlist_len > 100) IOMGR_Poll();
+    qsort((char*)alist->prlist_val,(int)alist->prlist_len,sizeof(afs_int32),IDCmp);
+    return PRSUCCESS;
+}
+#endif /* SUPERGROUPS */
+
 afs_int32 GetOwnedChain (ut, next, alist)
   struct ubik_trans *ut;
   afs_int32 *next;
@@ -1091,6 +1688,9 @@ afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
 {
     afs_int32 code;
     afs_int32 i, nptr, pos;
+#if defined(SUPERGROUPS)
+    afs_int32 nextpos;
+#endif
     struct contentry centry;
     struct prentry tentry, tent;
     afs_int32 loc;
@@ -1137,6 +1737,66 @@ afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
        code = pr_ReadEntry(at, 0, loc, &tentry);
        if (code) return PRDBFAIL;
 
+#if defined(SUPERGROUPS)
+       if (tentry.id > (afs_int32)ntohl(cheader.maxID))
+           code = set_header_word (at, maxID, htonl(tentry.id));
+       if (code) return PRDBFAIL; 
+
+       /* need to fix up: membership
+        * (supergroups?)
+        * ownership
+        */
+
+       for (i=0;i<PRSIZE;i++) {
+           if (tentry.entries[i] == PRBADID) continue;
+           if (tentry.entries[i] == 0) break;
+           if ((tentry.flags & PRGRP) && tentry.entries[i] < 0) { /* Supergroup */
+               return 5;       /* not yet, in short. */
+           }
+           else {
+               code = ChangeIDEntry (at, aid, newid, tentry.entries[i]);
+           }
+           if (code) return code;
+       }
+       for (pos = ntohl(tentry.owned); pos; pos = nextpos) {
+           code = pr_ReadEntry(at, 0, pos, &tent);
+           if (code) break;
+           tent.owner = newid;
+           nextpos = tent.nextOwned;
+           code = pr_WriteEntry(at, 0, pos, &tent);
+           if (code) break;
+       }
+       pos = tentry.next;
+       while (pos != NULL) {
+#define centry  (*(struct contentry*)&tent)
+           code = pr_ReadCoEntry(at,0,pos,&centry);
+           if ((centry.id != aid)
+                   || !(centry.flags & PRCONT)) {
+               fprintf(stderr,"ChangeEntry: bad database aid=%d centry.id=%d .flags=%d\n",
+                       aid, centry.id, centry.flags);
+               return PRDBBAD;
+           }
+           centry.id = newid;
+           for (i=0;i<COSIZE;i++) {
+               if (centry.entries[i] == PRBADID) continue;
+               if (centry.entries[i] == 0) break;
+               if ((centry.flags & PRGRP) && centry.entries[i] < 0) { /* Supergroup */
+                   return 5;   /* not yet, in short. */
+               }
+               else {
+                   code = ChangeIDEntry (at, aid, newid, centry.entries[i]);
+               }
+               if (code) return code;
+           }
+           code = pr_WriteCoEntry (at, 0, pos, &centry);
+           pos = centry.next;
+#undef centry
+       }
+       if (code) return code;
+
+#else /* SUPERGROUPS */
+
+
        /* Also change the references from the membership list */
        for (i=0; i<PRSIZE; i++) {
           if (tentry.entries[i] == PRBADID) continue;
@@ -1170,6 +1830,7 @@ afs_int32 ChangeEntry (at, aid, cid, name, oid, newid)
              if (code) return code;
           }
        }
+#endif /* SUPERGROUPS */
     }
 
     atsign = strchr(tentry.name, '@'); /* check for foreign entry */
index 048ff54..21d1554 100644 (file)
@@ -32,6 +32,10 @@ RCSID("$Header$");
 #include "ptserver.h"
 #include "pterror.h"
 
+#if defined(SUPERGROUPS)
+extern afs_int32 depthsg;
+#endif
+
 afs_int32 IDHash(x)
 afs_int32 x;
 {
@@ -759,16 +763,21 @@ afs_int32 aid;
 afs_int32 gid;
 {
     /* returns true if aid is a member of gid */
+#if !defined(SUPERGROUPS)
     struct prentry tentry;
     struct contentry centry;
     register afs_int32 code;
     afs_int32 i;
     afs_int32 loc;
+#endif
 
     /* special case anyuser and authuser */
     if (gid == ANYUSERID) return 1;
     if (gid == AUTHUSERID && aid != ANONYMOUSID) return 1;
     if ((gid == 0) || (aid == 0)) return 0;
+#if defined(SUPERGROUPS)
+    return IsAMemberOfSG(at, aid, gid, depthsg);
+#else
     loc = FindByID(at,gid);
     if (!loc) return 0;
     memset(&tentry, 0, sizeof(tentry));
@@ -793,4 +802,66 @@ afs_int32 gid;
        }
     }
     return 0;  /* actually, should never get here */
+#endif
 }
+
+
+#if defined(SUPERGROUPS)
+
+afs_int32 IsAMemberOfSG(at, aid, gid, depth)
+struct ubik_trans *at;
+afs_int32 aid;
+afs_int32 gid;
+afs_int32 depth;
+{
+    /* returns true if aid is a member of gid */
+    struct prentry tentry;
+    struct contentry centry;
+    register afs_int32 code;
+    afs_int32 i;
+    afs_int32 loc;
+
+    if (depth < 1) return 0;
+    loc = FindByID(at, gid);
+    if (!loc) return 0;
+    memset(&tentry, 0, sizeof(tentry));
+    code = pr_ReadEntry(at, 0, loc, &tentry);
+    if (code) return 0;
+    if (!(tentry.flags & PRGRP)) return 0;
+    for (i= 0;i<PRSIZE;i++) {
+       gid = tentry.entries[i];
+       if (gid == 0) return 0;
+       if (gid == aid) return 1;
+       if (gid == ANYUSERID) return 1;
+       if (gid == AUTHUSERID && aid != ANONYMOUSID) return 1;
+       if (gid < 0) {
+           IOMGR_Poll();
+           if (IsAMemberOfSG(at, aid, gid, depth-1))
+               return 1;
+       }
+    }
+    if (tentry.next) {
+       loc = tentry.next;
+       while (loc) {
+           memset(&centry, 0, sizeof(centry));
+           code = pr_ReadCoEntry(at, 0, loc, &centry);
+           if (code) return 0;
+           for (i=0;i<COSIZE;i++) {
+               gid = centry.entries[i];
+               if (gid == 0) return 0;
+               if (gid == aid) return 1;
+               if (gid == ANYUSERID) return 1;
+               if (gid == AUTHUSERID && aid != ANONYMOUSID) return 1;
+               if (gid < 0) {
+                   IOMGR_Poll();
+                   if (IsAMemberOfSG(at, aid, gid, depth-1))
+                       return 1;
+               }
+           }
+           loc = centry.next;
+       }
+    }
+    return 0;  /* actually, should never get here */
+}
+
+#endif /* SUPERGROUPS */