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.