[ --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,
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
${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 \
#
# 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
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
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}
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
char *whoami = "db_verify";
#define UBIK_HEADERSIZE 64
-
afs_int32 printheader(h)
struct prheader *h;
{
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;
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;
{
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;
/* 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);
/* 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");
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) {
else misc->freeLength = length;
return 0;
+#if defined(SUPERGROUPS)
+#undef g
+#endif
}
afs_int32 WalkOwnedChain (map, misc, ea, e)
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;
}
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;
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++) {
/* 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;
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);
}
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 */
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) &&
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);
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;
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,
}
/* 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));
goto abort;
}
memset(misc->idmap, 0, misc->idRange*sizeof(misc->idmap[0]));
+#endif /* SUPERGROUPS */
if (misc->verbose) {
printf ("\nChecking entry chains\n");
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 */
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: ");
--- /dev/null
+/*
+ * 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 = ↦ 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
--- /dev/null
+/*
+ * 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 *);
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;
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;
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);
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");
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
* 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
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
#define PRGETHOSTCPS 519
#define PRUPDATEENTRY 520
#define PRLISTENTRIES 521
-#define HIGHEST_OPCODE 521
-
+#define PRLISTSUPERGROUPS 530
+#define HIGHEST_OPCODE 530
* 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>
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();
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);
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);
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 */
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, ¢ry);
+ 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. */
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);
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,
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);
* 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>
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()
{
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;
}
"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;
{
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
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 */
}
* 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>
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;
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));
}
}
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();
}
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 */
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) {
rx_StartServer(1);
osi_audit (PTS_FinishEvent, -1, AUD_END);
+ exit(0);
}
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;
/* 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 */
* 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>
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
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,¢ry);
+ 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,¢ry);
+ 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,¢ry);
+ 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,¢ry);
+ 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*)¢ry,(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 */
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,¢ry);
}
+#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;
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) {
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;
}
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;
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;
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,¢ry);
+ 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,¢ry);
+ 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;
{
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;
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,¢ry);
+ 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, ¢ry);
+ 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;
if (code) return code;
}
}
+#endif /* SUPERGROUPS */
}
atsign = strchr(tentry.name, '@'); /* check for foreign entry */
#include "ptserver.h"
#include "pterror.h"
+#if defined(SUPERGROUPS)
+extern afs_int32 depthsg;
+#endif
+
afs_int32 IDHash(x)
afs_int32 x;
{
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));
}
}
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(¢ry, 0, sizeof(centry));
+ code = pr_ReadCoEntry(at, 0, loc, ¢ry);
+ 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 */