[comp.sources.unix] v19i042: A software configuration management system, Part29/33

rsalz@uunet.uu.net (Rich Salz) (06/07/89)

Submitted-by: Axel Mahler <unido!coma!axel>
Posting-number: Volume 19, Issue 42
Archive-name: shape/part29



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 29 (of 33)."
# Contents:  src/afs/afarchive.c
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:19 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/afs/afarchive.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/afs/afarchive.c'\"
else
echo shar: Extracting \"'src/afs/afarchive.c'\" \(35334 characters\)
sed "s/^X//" >'src/afs/afarchive.c' <<'END_OF_FILE'
X/*
X * Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X *  and U. Pralle
X * 
X * This software is published on an as-is basis. There is ABSOLUTELY NO
X * WARRANTY for any part of this software to work correctly or as described
X * in the manuals. We do not accept any liability for any kind of damage
X * caused by use of this software, such as loss of data, time, money, or 
X * effort.
X * 
X * Permission is granted to use, copy, modify, or distribute any part of
X * this software as long as this is done without asking for charge, and
X * provided that this copyright notice is retained as part of the source
X * files. You may charge a distribution fee for the physical act of
X * transferring a copy, and you may at your option offer warranty
X * protection in exchange for a fee.
X * 
X * Direct questions to: Tech. Univ. Berlin
X * 		     Wilfried Koch
X * 		     Sekr. FR 5-6 
X * 		     Franklinstr. 28/29
X * 		     D-1000 Berlin 10, West Germany
X * 
X * 		     Tel: +49-30-314-22972
X * 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X */
X/*
X *	Shape/AFS
X *
X *	afarchive.c -- read/write archives of attribute filesystem
X *
X *	Author: Andreas Lampen, TU-Berlin (andy@coma.UUCP)
X *					  (andy@db0tui62.BITNET)
X *
X *	$Header: afarchive.c[1.6] Wed Feb 22 16:27:01 1989 andy@coma published $
X *
X *	EXPORT:
X *	af_detarchive -- free descriptor for archive
X *      af_readdata -- read data from archive
X *	af_readattrs -- read attributes from archive
X *	af_writearchive -- write it
X */
X
X#include <stdio.h>
X#include <string.h>
X#ifdef SUNOS_4_0
X#include <strings.h>
X#endif
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "typeconv.h"
X#include "afsys.h"
X#include "afs.h"
X#include "afarchive.h"
X
X#ifdef MEMDEBUG
Xextern FILE *memprot;
X#endif
X
Xint     af_fhash();
XUid_t   getuid();
X
X/*==========================================================================
X * List of list-descriptors + hash table for faster access
X *
X * Allocated memory will never be freed up to now
X *
X *==========================================================================*/
X
X/* these two pointers should be local -- EXPORT only for debugging */
XLOCAL Af_revlist lst;
XEXPORT Af_revlist *af_lists = (Af_revlist *)0;  
X                                    /* base address of all list descriptors */
X
XEXPORT Af_revlist *af_freelist = &lst;  /* beginning of freelist */
X
XLOCAL Af_hash af_arhash;
Xbool  hinit = FALSE; /* indicate if hashtable is yet initialized */
X
X/*======================== init_ldes =======================================*/
X
XLOCAL Af_revlist *init_ldes (path, name, type)
X     char *path, *name, *type;
X{
X  register   i;
X  Af_revlist *list, *oldlist, **oldptr, *tail;
X  char       hashsymbol[MAXNAMLEN], *malloc(), *pathsym;
X
X  oldptr = &oldlist;
X  /* init hashtable if it is not yet done */
X  if (!hinit)
X    {
X      (void) af_hashinit (&af_arhash, AF_MAXLISTS, af_fhash);
X      hinit = TRUE;
X    }
X
X  pathsym = af_entersym (path);
X
X  (void) strcpy (hashsymbol, name);
X  if (type)
X    if (type[0])
X      {
X	(void) strcat (hashsymbol, ".");
X	(void) strcat (hashsymbol, type);
X      }
X    
X  /* if there are open archives check if desired archive is loaded yet */
X  if (af_lists != (Af_revlist *)0)
X    {
X      if (af_symlookup (&af_arhash, hashsymbol, (Af_revlist *)0, oldptr))
X	{
X	  /* found something */
X	  /* if it is the right list */
X	  if (oldlist->af_cattrs.af_syspath == pathsym)
X	    return (oldlist);
X	  /* else continue the search as long as there are entries */
X	  while (af_symlookup (&af_arhash, hashsymbol, oldlist, oldptr))
X	    {
X	      if (oldlist->af_cattrs.af_syspath == pathsym)
X		return (oldlist);
X	    }
X	}
X    }
X
X  /* if there are no more descriptors available - allocate new space */
X  if (af_freelist == (Af_revlist *)0)
X    {
X      if ((af_freelist = (Af_revlist *) malloc ((unsigned) (AF_LISTSEG * sizeof (Af_revlist)))) == (Af_revlist *)0)
X	FAIL ("readattrs", "malloc(i)", AF_ESYSERR, (Af_revlist *)0);
X
X      /* build up new freelist */
X      for (i=1; i<AF_LISTSEG; i++)
X	af_freelist[i-1].af_next = &(af_freelist[i]);
X      af_freelist[AF_LISTSEG-1].af_next = (Af_revlist *)0;
X    }
X
X  if (af_lists != (Af_revlist *)0)
X    {
X      tail = af_lists->af_next;
X      af_lists->af_next = af_freelist;
X      af_freelist = af_freelist->af_next;
X      list = af_lists->af_next;
X      bzero ((char *)list, sizeof (*list));
X
X      list->af_next = tail;
X    }
X  else
X    {
X      list = af_freelist;
X      af_freelist = af_freelist->af_next;
X      /* initialize whole struct (i.e. set af_next to "nil") */
X      bzero ((char *)list, sizeof (*list));
X      af_lists = list;
X    }
X
X  list->af_mem = (char *)0;
X  list->af_cattrs.af_host = af_gethostname ();
X  list->af_cattrs.af_syspath = pathsym;
X  list->af_lastmod = (time_t) 0;
X
X  /* add list to hashtable */
X  (void) af_hashsym (&af_arhash, hashsymbol, list);
X#ifdef MEMDEBUG
X  fprintf (memprot, "InitArch (%s)\n", hashsymbol);
X#endif
X
X  return (list);
X}
X
X
X/*==========================================================================
X *	af_detarchive -- free descriptor for archive
X *
X *
X *==========================================================================*/
X
XEXPORT af_detarchive (archive)
X     Af_revlist *archive;
X{
X  register int i;
X  Af_revlist *list;
X  char hashsymbol[MAXNAMLEN], *type;
X
X  /* if first list descriptor should be deleted - the base (af_lists) */
X  /* has to be preserved */
X  if (archive == af_lists)
X    af_lists = af_lists->af_next;
X  else
X    {
X      /* if archive list has more than one entry -- close gap in list */
X      if ((list = af_lists) != (Af_revlist *)0)
X	{
X	  while (list->af_next != archive)
X	    if ((list = list->af_next) == (Af_revlist *)0)
X	      FAIL ("detarchive", "archive lost", AF_EINTERNAL, ERROR);
X	  list->af_next = archive->af_next;
X	}
X    }
X
X  /* remove list from hash table */
X  type = af_aftype (archive->af_arfilename);
X  (void) strcpy (hashsymbol, af_afname (archive->af_arfilename));
X  if (type)
X    if (type[0])
X      {
X	(void) strcat (hashsymbol, ".");
X	(void) strcat (hashsymbol, type);
X      }
X  (void) af_delsym (&af_arhash, hashsymbol, archive);
X
X  /* hang free entry at the beginning of freelist */
X  archive->af_next = af_freelist;
X  af_freelist = archive;
X
X  /* free all allocated memory */
X  for (i=0; i<archive->af_listlen; i++)
X    {
X      if (archive->af_list[i].af_class & AF_VALID)
X	af_hashfree (&(archive->af_list[i].af_uhtab));
X    }
X  af_frmemlist (archive);
X
X  return (AF_OK);
X}
X
X/*==========================================================================
X *	firstitem, nextitem -- isolate items in input line
X *==========================================================================*/
X
XLOCAL char *firstitem (line)
X     char *line;
X{
X  char *sptr;
X
X  /* skip leading blank */
X  if ((sptr = index (&line[1], ' ')) == (char *)0)
X    sptr = index (&line[1], '\n');
X
X  *sptr = '\0';
X  return (&line[1]);
X}
X
XLOCAL char *nextitem (line)
X     char *line;
X{
X  char *sptr, *finptr;
X
X  sptr = &line[strlen(line)]+1; /* move to next entry */
X  if ((finptr = index (sptr, ' ')) == (char *)0)
X    finptr = index (sptr, '\n');
X  *finptr = '\0';
X
X  return (sptr);
X}
X  
X/*======================= rddata ====================================*/
X
XLOCAL af_rddata (file, dbuf, list)
X     FILE   *file;
X     char   *dbuf;
X     Af_revlist *list;
X{
X  char	idstr[AF_IDSTRLEN+1], *itemptr, line[AF_LINESIZ];
X  int   i, gen, rev, maxindex;
X  off_t	size, dpos = 0;
X
X  /* if there is a valid busy version */
X  if (list->af_list[0].af_class & AF_VALID)
X    maxindex = list->af_nrevs;
X  else
X    maxindex = list->af_nrevs+1;
X
X  idstr[AF_IDSTRLEN] = '\0';
X  /* skip busy version */
X  for (i=1; i < maxindex; i++)
X    {
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      if (strcmp (idstr, AF_NOTEID))
X	FAIL ("rddata", "wrong note-ID in datafile", AF_EINCONSIST, ERROR);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      gen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      rev = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      size = (off_t) atoi (itemptr);
X
X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
X	FAIL ("rddata", "wrong version in datafile", AF_EINCONSIST, ERROR);
X
X      /* read note */
X      (void) fread (&(dbuf[dpos]), sizeof(char), (Size_t) size, file);
X      list->af_list[i].af_notesize = size;
X      list->af_list[i].af_note = &(dbuf[dpos]);
X      /* replace newline by nullbyte */
X      list->af_list[i].af_note[size-sizeof(char)] = '\0';
X      dpos = dpos+size;
X
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      if (strcmp (idstr, AF_DATAID))
X	FAIL ("rddata", "wrong data-ID in datafile", AF_EINCONSIST, ERROR);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      gen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      rev = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      itemptr = nextitem (itemptr);
X      size = (off_t) atoi (itemptr);
X
X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
X	FAIL ("rddata", "wrong version in datafile", AF_EINCONSIST, ERROR);
X
X      /* read data */
X      (void) fread (&(dbuf[dpos]), sizeof(char), (Size_t) size, file);
X      list->af_list[i].af_data = &(dbuf[dpos]);
X      dpos = dpos+size;
X    }
X  return (AF_OK);
X} /* af_rddata */
X
X/*==========================================================================
X *	af_readdata -- read notes and data section of archive file
X *
X *
X *==========================================================================*/
X
XEXPORT af_readdata (list)
X     Af_revlist *list;
X{
X  char *data, idstr[AF_SEGSTRLEN+1], archname[MAXNAMLEN], line[AF_LINESIZ];
X  FILE *archfile;
X  short version;
X
X  /* if notes are already loaded */
X  if ((list->af_extent & AF_DATA) == AF_DATA)
X    return (AF_OK);
X
X  (void) strcpy (archname, list->af_arfilename);
X  archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
X  if ((archfile = fopen (archname, "r")) == (FILE *)0)
X    FAIL ("readdata", "", AF_ENOAFSFILE, ERROR);
X
X  idstr[AF_SEGSTRLEN] = '\0';
X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
X  if (strncmp (idstr, AF_DATAHEADER, AF_SEGSTRLEN))
X    FAIL ("readdata", "wrong header in datafile", AF_EINCONSIST, ERROR);
X
X  (void) fgets (line, AF_LINESIZ, archfile);
X  version = atoi (line);
X  if (version != AF_ARCURVERS)
X    FAIL ("readdata", "unknown archive format version", AF_EINCONSIST, ERROR);
X
X  /* allocate memory for data */
X  if ((data = af_malloc (list, (unsigned) list->af_datasize)) == (char *)0)
X    FAIL ("readdata", "malloc", AF_ESYSERR, ERROR);
X
X  if (af_rddata (archfile, data, list) != AF_OK)
X    return (ERROR);
X
X  list->af_extent |= AF_DATA;
X  (void) fclose (archfile);
X  return (AF_OK);
X}
X
X/*======================= rdattrs ====================================*/
X
XLOCAL af_rdattrs (file, list, bibufptr)
X     FILE	 *file;
X     Af_revlist  *list;
X     struct stat *bibufptr;
X{
X  char idstr[AF_IDSTRLEN+1], *itemptr, line[AF_LINESIZ];
X  int  i;
X  bool writeok;
X  Af_user *user, *owner, *af_garown();
X
X  /* skip idstring */
X  idstr[AF_IDSTRLEN] = '\0';
X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
X  
X  /* read constant attributes and variant of busy version */
X  (void) fgets (line, AF_LINESIZ, file);
X
X  /* check location (only host is checked up to now) */
X  /* path, name and type could be checked too */
X
X  itemptr = firstitem (line); /* host */
X  if (strcmp (list->af_cattrs.af_host, itemptr))
X    {
X      /* FAIL ("rdattrs", "", AF_ELOC, ERROR); -- replaced by: */
X      af_wng ("readattrs", "wrong hostname in archive file");
X      list->af_cattrs.af_host = af_entersym (itemptr);
X    }
X  itemptr = nextitem (itemptr); /* path - skipped ... */
X  itemptr = nextitem (itemptr); /* name - skipped ... */
X  itemptr = nextitem (itemptr); /* type - skipped ... */
X
X  itemptr = nextitem (itemptr); /* variant */
X  if (strcmp (itemptr, AF_NOSTRING))
X    list->af_list[0].af_variant = af_entersym (itemptr);
X  else
X    list->af_list[0].af_variant = (char *)0;
X
X  /* get owner of archive directory */
X  if ((owner = af_garown (list->af_arfilename, &writeok)) == (Af_user *)0)
X    FAIL ("rdattrs", "cannot get owner of archive", AF_EINTERNAL, ERROR);
X  list->af_cattrs.af_ownname = af_entersym (owner->af_username);
X  list->af_cattrs.af_ownhost = af_enterhost (owner->af_userhost);
X
X  if (writeok)
X    list->af_extent |= AF_UXWRITE;
X  
X  /* read owner from archive */
X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
X  (void) fgets (line, AF_LINESIZ, file); /* name and host of owner */
X  /* plausibility of owner should be checked here */
X
X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
X  (void) fgets (line, AF_LINESIZ, file); /* predecessor of busy object */
X  itemptr = firstitem (line);
X  list->af_list[0].af_predgen = atoi (itemptr);
X  itemptr = nextitem (itemptr);
X  list->af_list[0].af_predrev = atoi (itemptr);
X
X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
X  (void) fgets (line, AF_LINESIZ, file); /* locker */
X  itemptr = firstitem (line);
X  if (strcmp (itemptr, AF_NOSTRING))
X    {
X      list->af_list[0].af_lckname = af_entersym (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[0].af_lckhost = af_enterhost (itemptr);
X    }
X  else
X    {
X      list->af_list[0].af_lckname = (char *)0;
X      itemptr = nextitem (itemptr);
X      list->af_list[0].af_lckhost = (char *)0;
X    }
X  itemptr = nextitem (itemptr);
X  list->af_list[0].af_ltime = (time_t)atoi(itemptr);
X
X  /* initialize and attributes for busy version */
X  list->af_list[0].af_gen = AF_BUSYVERS;
X  list->af_list[0].af_rev = AF_BUSYVERS;
X  list->af_list[0].af_state = AF_BUSY;
X  list->af_list[0].af_stime = AF_NOTIME;
X  list->af_list[0].af_udanum = 0;
X  list->af_list[0].af_repr = AF_FILE;
X  list->af_list[0].af_dsize = (off_t) 0;
X  list->af_list[0].af_data = (char *)0;
X  list->af_list[0].af_hashname = (char *)0;
X  list->af_list[0].af_nlinks = 0;
X  list->af_list[0].af_succgen = AF_NOVNUM;
X  list->af_list[0].af_succrev = AF_NOVNUM;
X
X  if (bibufptr->st_ino) /* if there is a busy version */
X    {
X      list->af_list[0].af_class = AF_VALID;
X      if ((user = af_getuser (bibufptr->st_uid)) == (Af_user *)0)
X	{
X	  af_wng ("rdattrs", "invalid userID in inode of busy file");
X	  user = af_getuser (getuid());
X	}
X      list->af_list[0].af_auname = af_entersym (user->af_username);
X      list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
X      list->af_list[0].af_mode = (u_short) bibufptr->st_mode;
X      list->af_list[0].af_mtime = (time_t) af_cvttime (bibufptr->st_mtime);
X      list->af_list[0].af_atime = (time_t) af_cvttime (bibufptr->st_atime);
X      list->af_list[0].af_ctime = (time_t) af_cvttime (bibufptr->st_ctime);
X      list->af_list[0].af_fsize = (off_t) bibufptr->st_size;
X    }
X  else
X    {
X      list->af_list[0].af_class = 0;
X      list->af_list[0].af_auname = (char *)0;
X      list->af_list[0].af_auhost = (char *)0;
X      list->af_list[0].af_mode = AF_NOMODE;
X      list->af_list[0].af_mtime = AF_NOTIME;
X      list->af_list[0].af_atime = AF_NOTIME;
X      list->af_list[0].af_ctime = AF_NOTIME;
X      list->af_list[0].af_fsize = AF_NOTIME;
X    }
X      
X  /* read list */
X  for (i=1; i < list->af_nrevs; i++)
X    {
X      /* do initializations */
X      list->af_list[i].af_class = AF_VALID;
X      list->af_list[i].af_notesize = 0;
X      list->af_list[i].af_note = (char *)0;
X      list->af_list[i].af_data = (char *)0;
X      list->af_list[i].af_nlinks = 0;
X      list->af_list[i].af_hashname = (char *)0;
X
X      /* enter name (set a pointer to the name-field of af_list[0]) */
X      /* skip position 0 */
X      if (i != 0)
X	{
X	  list->af_list[i].af_name = list->af_list[0].af_name;
X	  list->af_list[i].af_type = list->af_list[0].af_type;
X	}
X
X      /* read revision ID */
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      if (strcmp (idstr, AF_REVID)) /* could be done for every field */
X	FAIL ("rdattrs", 
X	      "wrong revision-ID in archive file", AF_EINCONSIST, ERROR);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      list->af_list[i].af_gen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_rev = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_state = (short) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      (void) sscanf (itemptr, "%ho", &(list->af_list[i].af_mode));
X      itemptr = nextitem (itemptr);
X      if (strcmp (itemptr, AF_NOSTRING))
X	list->af_list[i].af_variant = af_entersym (itemptr);
X      else
X	list->af_list[i].af_variant = (char *)0;
X      
X      /* read author*/
X      (void) fgetc (file); /* skip tab */
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      (void) fgets (line, AF_LINESIZ, file); /* predecessor of busy object */
X      itemptr = firstitem (line);
X      list->af_list[i].af_auname = af_entersym (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_auhost = af_enterhost (itemptr);
X      itemptr = nextitem (itemptr);
X      if (strcmp (itemptr, AF_NOSTRING))
X      	{
X	  list->af_list[i].af_lckname = af_entersym (itemptr);
X	  itemptr = nextitem (itemptr);
X	  list->af_list[i].af_lckhost = af_enterhost (itemptr);
X	}
X      else
X	{
X	  list->af_list[i].af_lckname = (char *)0;
X	  itemptr = nextitem (itemptr);
X	  list->af_list[i].af_lckhost = (char *)0;
X	}
X
X      /* read dates */
X      (void) fgetc (file); /* skip tab */
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      list->af_list[i].af_mtime = (time_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_atime = (time_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_ctime = (time_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_stime = (time_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_ltime = (time_t) atoi (itemptr);
X
X      /* read kind of representation */
X      (void) fgetc (file); /* skip tab */
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      list->af_list[i].af_repr = (short) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_fsize = (off_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_dsize = (off_t) atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_succgen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_succrev = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_predgen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      list->af_list[i].af_predrev = atoi (itemptr);
X    }
X  if (!(bibufptr->st_ino)) /* if there is no busy version */
X    list->af_nrevs--;
X  
X  return (AF_OK);
X} /* af_rdattrs */
X
X/*======================= rdudas ====================================*/
X
X#define AF_UDASEGSIZ 8
X
XLOCAL af_rdudas (file, list)
X     FILE       *file;
X     Af_revlist *list;
X{
X  char	idstr[AF_IDSTRLEN+1], *udabuf, *malloc(), *realloc();
X  char  *itemptr, line[AF_LINESIZ];
X  int	c, i, j, gen, rev, maxindex;
X
X  /* if there is a valid busy version */
X  if (list->af_list[0].af_class & AF_VALID)
X    maxindex = list->af_nrevs;
X  else
X    maxindex = list->af_nrevs+1;
X
X  (void) getc (file); /* skip newline */
X  idstr[AF_IDSTRLEN] = '\0';
X  for (i=0; i < maxindex; i++)
X    {
X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
X      if (strcmp (idstr, AF_UDAID))
X	FAIL ("rdudas", "wrong uda-ID in archive file", AF_EINCONSIST, ERROR);
X      (void) fgets (line, AF_LINESIZ, file);
X      itemptr = firstitem (line);
X      gen = atoi (itemptr);
X      itemptr = nextitem (itemptr);
X      rev = atoi (itemptr);
X
X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
X	FAIL ("rdudas", "wrong version in archive file", AF_EINCONSIST, ERROR);
X      
X      /* build up hashlist and read user define attributes */
X      if (af_hashinit (&list->af_list[i].af_uhtab, AF_MAXUDAS, af_fhash)
X	                                                         == ERROR)
X	return (ERROR);
X
X      if (i == 0) /* initalize only once */
X	{
X	  if ((udabuf = malloc ((unsigned) (AF_UDASEGSIZ * sizeof (char)))) == (char *)0)
X	    FAIL ("rdudas", "malloc", AF_ESYSERR, ERROR);
X	}
X
X      /* if there is *no* valid busy version, skip the user defined */
X      /* attributes for the busy version */
X      if ((i==0) && !(list->af_list[0].af_class & AF_VALID))
X	{
X	  while (TRUE)
X	    {
X	      if ((c = getc (file)) == '\0')
X		{
X		  if ((c = getc (file)) == '\0')
X		    break;
X		}
X	    }
X	  (void) getc (file); /* skip trailing newline char */
X	  continue;
X	}
X
X      j = 0;
X      while (TRUE)
X	{
X	  if ((udabuf[j] = getc (file)) == '\0')
X	    { 
X	      if (j != 0)
X		{
X		  (void) af_hashsym (&list->af_list[i].af_uhtab, udabuf, (Af_revlist *)0);
X#ifdef MEMDEBUG
X		  fprintf (memprot, "Uda (%s)\n", udabuf);
X#endif
X		  list->af_list[i].af_udanum++;
X		}
X	      /* a second nullbyte indicates the end of the list of udas */
X	      if ((c = getc (file)) == '\0')
X		break;
X	      udabuf[0] = c;
X	      j = 1;
X	    }
X	  else
X	    {
X	      j++;
X	      if ((j % AF_UDASEGSIZ) == 0) /* if segment is full */
X		{
X		  if ((udabuf = realloc (udabuf, (unsigned) ((j + AF_UDASEGSIZ) * sizeof (char)))) == (char *)0) 
X		    FAIL ("rdudas", "realloc", AF_ESYSERR, ERROR);
X		}
X	    }
X	}
X      (void) getc (file); /* skip trailing newline char */
X    }
X  free (udabuf);
X  return (AF_OK);
X} /* af_rdudas */
X
X/*==========================================================================
X *	af_readattrs -- read attributes from archive file
X *                      
X *
X *==========================================================================*/
X
XEXPORT Af_revlist *af_readattrs (path, name, type, mode)
X     char *path, *name, *type;
X     bool *mode;
X{
X  char	  idstr[AF_SEGSTRLEN+1], line[AF_LINESIZ], *itemptr;
X  FILE	  *archfile;
X  struct stat bibuf, aibuf;
X  Af_revlist *list, *init_ldes();
X  short   version;
X  bool    writeok;
X  Af_user *user, *owner, *af_garown();
X
X  if ((list = init_ldes (path, name, type)) == (Af_revlist *)0)
X    return ((Af_revlist *)0);
X
X  /* if attributes are already loaded */
X  if ((list->af_extent & AF_ATTRS) == AF_ATTRS)
X    {
X      if (*mode == FALSE)
X	{
X	  /* see if busy version has changed */
X	  if (lstat (list->af_busyfilename, &bibuf) == ERROR)
X	    bibuf.st_ctime = AF_NOTIME;
X	  if (bibuf.st_ctime != list->af_list[0].af_ctime)
X	    {
X	      /* update busy version */
X	      if (!(list->af_list[0].af_class & AF_VALID))
X		{
X		  list->af_nrevs++;
X		  if (af_hashinit (&list->af_list[0].af_uhtab,
X				   AF_MAXUDAS, af_fhash) == ERROR)
X		    return ((Af_revlist *)0);
X		  list->af_list[0].af_class = AF_VALID;
X		}
X	      if ((user = af_getuser (bibuf.st_uid)) == (Af_user *)0)
X		{
X		  af_wng ("readattrs", "invalid userID in inode of busy file");
X		  user = af_getuser (getuid());
X		}
X	      list->af_list[0].af_auname = af_entersym (user->af_username);
X	      list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
X	      list->af_list[0].af_mode = (u_short) bibuf.st_mode;
X	      list->af_list[0].af_mtime = (time_t) af_cvttime (bibuf.st_mtime);
X	      list->af_list[0].af_atime = (time_t) af_cvttime (bibuf.st_atime);
X	      list->af_list[0].af_ctime = (time_t) af_cvttime (bibuf.st_ctime);
X	      list->af_list[0].af_fsize = (off_t) bibuf.st_size;
X	    }
X	}
X      *mode = TRUE;
X      return (list);
X    }
X  else
X    {
X      *mode = FALSE;
X    }
X
X  if ((list->af_busyfilename = af_gbusname (list->af_cattrs.af_syspath,
X					     name, type)) == (char *)0)
X    return ((Af_revlist *)0);
X  
X  list->af_arfilename = af_garname (list->af_cattrs.af_syspath, name, type);
X  list->af_extent |= AF_ARCHIVE;
X
X  if (lstat (list->af_busyfilename, &bibuf) == ERROR)
X    bibuf.st_ino = 0;
X
X  /* open archive */
X  if ((list->af_arfilename == (char *)0) ||
X      ((archfile = fopen (list->af_arfilename, "r")) == (FILE *)0))
X    {
X      if (bibuf.st_ino == 0) /* no busy file */
X	{
X	  (void) af_detarchive (list);
X	  SFAIL ("readattrs", "", AF_ENOAFSFILE, (Af_revlist *)0);
X	}
X      list->af_nrevs = 1;
X      list->af_listlen = AF_NEWREVS;
X      list->af_extent |= AF_ALLSEGS;
X      list->af_datasize = 0;
X
X      /* determine author of busy file */
X      if ((user = af_getuser (bibuf.st_uid)) == (Af_user *)0)
X	{
X	  af_wng ("readattrs", "invalid userID in inode of busy file");
X	  user = af_getuser (getuid());
X	}
X
X      /* if an archive-directory exists, get its owner */
X      if ((owner = af_garown (list->af_arfilename, &writeok)) == (Af_user *)0)
X	{
X	  list->af_cattrs.af_ownname = af_entersym (user->af_username);
X	  list->af_cattrs.af_ownhost = af_enterhost (user->af_userhost);
X	}
X      else
X	{
X	  list->af_cattrs.af_ownname = af_entersym (owner->af_username);
X	  list->af_cattrs.af_ownhost = af_enterhost (owner->af_userhost);
X	}
X      if (writeok)
X	list->af_extent |= AF_UXWRITE;
X      
X      if ((list->af_list = (Af_vattrs *)af_malloc (list, (unsigned) (list->af_listlen * sizeof(Af_vattrs)))) == (Af_vattrs *)0)
X	FAIL ("readattrs", "malloc,1", AF_ESYSERR, (Af_revlist *)0);
X      
X      bzero ((char *)list->af_list, list->af_listlen * sizeof (Af_vattrs));
X      /* init attrbuf for busy version  (relevant attrs only) */
X      list->af_list[0].af_name = af_entersym (name);
X      list->af_list[0].af_type = af_entersym (type);
X      list->af_list[0].af_gen = AF_BUSYVERS;
X      list->af_list[0].af_rev = AF_BUSYVERS;
X      list->af_list[0].af_variant = (char *)0;
X      list->af_list[0].af_state = AF_BUSY;
X      list->af_list[0].af_class = AF_VALID;
X      list->af_list[0].af_auname = af_entersym (user->af_username);
X      list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
X      list->af_list[0].af_mode = (u_short) bibuf.st_mode;
X      list->af_list[0].af_lckname = (char *)0;
X      list->af_list[0].af_lckhost = (char *)0;
X      list->af_list[0].af_mtime = (time_t) af_cvttime (bibuf.st_mtime);
X      list->af_list[0].af_atime = (time_t) af_cvttime (bibuf.st_atime);
X      list->af_list[0].af_ctime = (time_t) af_cvttime (bibuf.st_ctime);
X      list->af_list[0].af_stime = AF_NOTIME;
X      list->af_list[0].af_ltime = AF_NOTIME;
X      list->af_list[0].af_notesize = 1;
X      list->af_list[0].af_note = (char *)0;
X      list->af_list[0].af_udanum = 0;
X      if (af_hashinit (&list->af_list[0].af_uhtab, AF_MAXUDAS, af_fhash)
X	                                                         == ERROR)
X	return ((Af_revlist *)0);
X      list->af_list[0].af_repr = AF_FILE;
X      list->af_list[0].af_fsize = (off_t) bibuf.st_size;
X      list->af_list[0].af_dsize = 0;
X      list->af_list[0].af_data = (char *)0;
X      list->af_list[0].af_hashname = (char *)0;
X      list->af_list[0].af_nlinks = 0;
X      list->af_list[0].af_succgen = AF_NOVNUM;
X      list->af_list[0].af_succrev = AF_NOVNUM;
X      list->af_list[0].af_predgen = AF_NOVNUM;
X      list->af_list[0].af_predrev = AF_NOVNUM;
X      return (list);
X    }
X  
X  /* record date of last modification */
X  (void) lstat (list->af_arfilename, &aibuf);
X  list->af_lastmod = (time_t) af_cvttime (aibuf.st_mtime);
X
X  /* archive file ??? */
X  idstr[AF_SEGSTRLEN] = '\0';
X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
X  if (strncmp (idstr, AF_ARHEADER, AF_SEGSTRLEN))
X    FAIL ("readattrs",
X	  "wrong header in archive file", AF_EINCONSIST, (Af_revlist *)0);
X  
X  /* read header */
X  (void) fgets (line, AF_LINESIZ, archfile);
X  itemptr = firstitem (line);
X  version = atoi (itemptr);
X  if (version != AF_ARCURVERS)
X    FAIL ("readattrs", 
X	  "unknown archive format version", AF_EINCONSIST, (Af_revlist *)0);
X  itemptr = nextitem (itemptr);
X  list->af_nrevs = atoi (itemptr);
X  itemptr = nextitem (itemptr);
X  list->af_datasize = atoi (itemptr);
X
X  /* alloc memory for revision list (plus space for new revs) */
X  list->af_listlen = list->af_nrevs + AF_NEWREVS;
X  if ((list->af_list = (Af_vattrs *)af_malloc (list, (unsigned) (list->af_listlen * sizeof(Af_vattrs)))) == (Af_vattrs *)0)
X    FAIL ("readattrs", "malloc,2", AF_ESYSERR, (Af_revlist *)0);
X
X  bzero ((char *) list->af_list, list->af_listlen * sizeof (Af_vattrs));
X
X  /* enter name and type */
X  list->af_list[0].af_name = af_entersym (name);
X  list->af_list[0].af_type = af_entersym (type);
X
X  if (af_rdattrs (archfile, list, &bibuf) != AF_OK)
X    return ((Af_revlist *)0);
X
X  /* read id string for user defined attributes section*/
X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
X  if (strncmp (idstr, AF_UDASEG, AF_SEGSTRLEN))
X    FAIL ("readattrs",
X	  "wrong udaseg-ID in archive file", AF_EINCONSIST, (Af_revlist *)0);
X
X  if (af_rdudas (archfile, list) != AF_OK)
X    return ((Af_revlist *)0);
X
X  list->af_extent |= (AF_ATTRS | AF_COMPLETE);
X  (void) fclose (archfile);
X  return (list);
X} /* af_readattrs */
X
X
X/*==========================================================================
X *	writearchive -- write archive file
X *
X *
X *==========================================================================*/
X
XEXPORT af_writearchive (list)
X     Af_revlist *list;
X{
X  int   i, j, maxindex;
X  FILE	*tmpfile, *datafile;
X  char  tmpname[MAXNAMLEN], dataname[MAXNAMLEN], *ptrlist[AF_MAXUDAS];
X  char  archname[MAXNAMLEN];
X  off_t	datasize;
X  Af_key *busyptr, *af_gbuskey();
X
X  /* File locking mechanism should be inserted here */
X
X  /* if all revisions have been removed */
X  if (list->af_nrevs == 0)
X    {
X      (void) af_unlink (list->af_arfilename);
X      (void) strcpy (archname, list->af_arfilename);
X      archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
X      (void) af_unlink (archname);
X      return (AF_OK);
X    }
X
X  (void) strcpy (tmpname, list->af_arfilename); 
X  tmpname[strlen(tmpname) - sizeof(char)] = AF_ARCHTMP;
X  af_regtmpfile (tmpname);
X  /* open tmpfile */
X  if ((tmpfile = fopen (tmpname, "w")) == (FILE *)0)
X    FAIL ("writearchive", "fopen", AF_ESYSERR, ERROR);
X
X  /* if there is no busy version - increase "nrevs" temporarily */
X  busyptr = af_gbuskey (list);
X  if (!(VATTR(busyptr).af_class & AF_VALID))
X    list->af_nrevs++;
X
X  /* write header */
X  fprintf (tmpfile, "%s %d %d %ld\n", AF_ARHEADER, AF_ARCURVERS,
X	   list->af_nrevs, list->af_datasize);
X
X  /* write constant attributes */
X  fprintf (tmpfile, "%s %s %s %s %s %s\n", AF_NAMEID, 
X	   list->af_cattrs.af_host,
X	   list->af_cattrs.af_syspath,
X	   list->af_list[0].af_name,
X	   NOTMT (list->af_list[0].af_type),
X	   NOTMT (list->af_list[0].af_variant));
X
X  /* write owner */
X  fprintf (tmpfile, "%s %s %s\n", AF_OWNID,
X	   list->af_cattrs.af_ownname,
X	   list->af_cattrs.af_ownhost);
X
X
X  /* write predecessor and locker of busy version */
X  fprintf (tmpfile, "%s %d %d\n%s %s %s %d\n", AF_PRDID,
X	   VATTR(busyptr).af_predgen,
X	   VATTR(busyptr).af_predrev, AF_LOCKID,
X	   NOTMT (VATTR(busyptr).af_lckname),
X	   NOTMT (VATTR(busyptr).af_lckhost),
X	   VATTR(busyptr).af_ltime);
X
X  /* write list of version attributes */
X  maxindex = list->af_nrevs;
X  for (i=1; i < maxindex; i++)
X    {
X      /* skip deleted versions */
X      if (!(list->af_list[i].af_class & AF_VALID))
X	{
X	  maxindex++;
X	  continue;
X	}
X
X      /* write revision ID */
X      fprintf (tmpfile, "%s %d %d %d %o %s\n", AF_REVID, 
X	       list->af_list[i].af_gen,
X	       list->af_list[i].af_rev,
X	       list->af_list[i].af_state,
X	       list->af_list[i].af_mode,
X	       NOTMT (list->af_list[i].af_variant));
X
X      /* write author */
X      fprintf (tmpfile, "\t%s %s %s %s %s\n", AF_AUTHORID,
X	       list->af_list[i].af_auname,
X	       list->af_list[i].af_auhost,
X	       NOTMT (list->af_list[i].af_lckname),
X	       NOTMT (list->af_list[i].af_lckhost));
X
X      /* write dates */
X      fprintf (tmpfile, "\t%s %ld %ld %ld %ld %ld\n", AF_DATEID,
X	       list->af_list[i].af_mtime,
X	       list->af_list[i].af_atime,
X	       list->af_list[i].af_ctime,
X	       list->af_list[i].af_stime,
X	       list->af_list[i].af_ltime);
X
X      /* write kind of representation and tree connects */
X      fprintf (tmpfile, "\t%s %d %ld %ld %d %d %d %d\n", AF_REPRID,
X	       list->af_list[i].af_repr,
X	       list->af_list[i].af_fsize,
X	       list->af_list[i].af_dsize,
X	       list->af_list[i].af_succgen,
X	       list->af_list[i].af_succrev,
X	       list->af_list[i].af_predgen,
X	       list->af_list[i].af_predrev);
X    }
X
X  /* write user defined attributes */
X  fprintf (tmpfile, "%s\n", AF_UDASEG);
X  maxindex = list->af_nrevs;
X  for (i=0; i < maxindex; i++)
X    {
X      /* skip deleted versions but not the busy version */
X      if (!(list->af_list[i].af_class & AF_VALID) && 
X	  (list->af_list[i].af_state != AF_BUSY))
X	{ maxindex++; continue;	}
X
X      fprintf (tmpfile, "%s %d %d\n", AF_UDAID,
X	       list->af_list[i].af_gen,
X	       list->af_list[i].af_rev);
X      (void) af_lhashsyms (&list->af_list[i].af_uhtab, ptrlist);
X      j=0;
X      while (ptrlist[j])
X	fprintf (tmpfile, "%s%c", ptrlist[j++], '\0');
X      if (j==0) /* if no user defined attribute has been written */
X	(void) putc ('\0', tmpfile);
X      (void) putc ('\0', tmpfile);
X      (void) putc ('\n', tmpfile);
X    }
X  (void) fclose (tmpfile);
X
X  /* if data have been manipulated - write data file */
X  if ((list->af_extent & AF_DATA) == AF_DATA)
X    {
X      (void) strcpy (dataname, list->af_arfilename);
X      dataname[strlen(dataname) - sizeof(char)] = AF_DATATMP;
X      af_regtmpfile (dataname);
X      /* open tmpfile for data */
X      if ((datafile = fopen (dataname, "w")) == (FILE *)0)
X	FAIL ("writearchive", "fopen", AF_ESYSERR, ERROR);
X
X      /* write notes and data */
X      fprintf (datafile, "%s %d\n", AF_DATAHEADER, AF_ARCURVERS);
X      
X      maxindex = list->af_nrevs;
X      for (i=1; i < maxindex; i++)
X	{
X	  /* skip deleted versions */
X	  if (!(list->af_list[i].af_class & AF_VALID))
X	    { maxindex++; continue; }
X	  
X	  fprintf (datafile, "%s %d %d %ld\n", AF_NOTEID,
X		   list->af_list[i].af_gen,
X		   list->af_list[i].af_rev,
X		   list->af_list[i].af_notesize);
X	  (void) fwrite (list->af_list[i].af_note, sizeof(char), (Size_t) list->af_list[i].af_notesize - sizeof(char), datafile);
X	  (void) putc ('\n', datafile);
X
X	  if (list->af_list[i].af_repr == AF_CHUNK)
X	    datasize = list->af_list[i].af_fsize;
X	  else datasize = list->af_list[i].af_dsize;
X	  fprintf (datafile, "%s %d %d %d %ld\n", AF_DATAID,
X		   list->af_list[i].af_gen,
X		   list->af_list[i].af_rev,
X		   list->af_list[i].af_repr, datasize);
X
X	  (void) fwrite (list->af_list[i].af_data, sizeof(char), (Size_t) datasize, datafile);
X	}
X      (void) fclose (datafile);
X    }
X
X  af_unregtmpfile (tmpname);
X  (void) af_unlink (list->af_arfilename);
X  if (af_syslink (tmpname, list->af_arfilename) == ERROR)
X    FAIL ("writearchive", "link", AF_ESYSERR, ERROR);
X
X  (void) af_uchmod (list->af_arfilename, AF_ARCHMODE);
X  (void) af_unlink (tmpname);
X
X  /* if the data file has been written */
X  if ((list->af_extent & AF_DATA) == AF_DATA)
X    {
X      (void) strcpy (archname, list->af_arfilename);
X      archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
X      af_unregtmpfile (dataname);
X      (void) af_unlink (archname);
X      if (af_syslink (dataname, archname) == ERROR)
X	FAIL ("writearchive", "link", AF_ESYSERR, ERROR);
X      (void) af_uchmod (archname, AF_ARCHMODE);
X      (void) af_unlink (dataname);
X    }
X
X  /* decrease "nrevs" again (see beginning of procedure */
X  if (!(VATTR(busyptr).af_class & AF_VALID))
X    list->af_nrevs--;
X  
X  return (AF_OK);
X} /* af_writearchive */
X
END_OF_FILE
if test 35334 -ne `wc -c <'src/afs/afarchive.c'`; then
    echo shar: \"'src/afs/afarchive.c'\" unpacked with wrong size!
fi
# end of 'src/afs/afarchive.c'
fi
echo shar: End of archive 29 \(of 33\).
cp /dev/null ark29isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 33 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.