home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume19 / shape / part29 < prev    next >
Text File  |  1989-05-31  |  38KB  |  1,136 lines

  1. Subject:  v19i042:  A software configuration management system, Part29/33
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Axel Mahler <unido!coma!axel>
  7. Posting-number: Volume 19, Issue 42
  8. Archive-name: shape/part29
  9.  
  10.  
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 29 (of 33)."
  19. # Contents:  src/afs/afarchive.c
  20. # Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:19 1989
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'src/afs/afarchive.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'src/afs/afarchive.c'\"
  24. else
  25. echo shar: Extracting \"'src/afs/afarchive.c'\" \(35334 characters\)
  26. sed "s/^X//" >'src/afs/afarchive.c' <<'END_OF_FILE'
  27. X/*
  28. X * Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
  29. X *  and U. Pralle
  30. X * 
  31. X * This software is published on an as-is basis. There is ABSOLUTELY NO
  32. X * WARRANTY for any part of this software to work correctly or as described
  33. X * in the manuals. We do not accept any liability for any kind of damage
  34. X * caused by use of this software, such as loss of data, time, money, or 
  35. X * effort.
  36. X * 
  37. X * Permission is granted to use, copy, modify, or distribute any part of
  38. X * this software as long as this is done without asking for charge, and
  39. X * provided that this copyright notice is retained as part of the source
  40. X * files. You may charge a distribution fee for the physical act of
  41. X * transferring a copy, and you may at your option offer warranty
  42. X * protection in exchange for a fee.
  43. X * 
  44. X * Direct questions to: Tech. Univ. Berlin
  45. X *              Wilfried Koch
  46. X *              Sekr. FR 5-6 
  47. X *              Franklinstr. 28/29
  48. X *              D-1000 Berlin 10, West Germany
  49. X * 
  50. X *              Tel: +49-30-314-22972
  51. X *              E-mail: shape@coma.uucp or shape@db0tui62.bitnet
  52. X */
  53. X/*
  54. X *    Shape/AFS
  55. X *
  56. X *    afarchive.c -- read/write archives of attribute filesystem
  57. X *
  58. X *    Author: Andreas Lampen, TU-Berlin (andy@coma.UUCP)
  59. X *                      (andy@db0tui62.BITNET)
  60. X *
  61. X *    $Header: afarchive.c[1.6] Wed Feb 22 16:27:01 1989 andy@coma published $
  62. X *
  63. X *    EXPORT:
  64. X *    af_detarchive -- free descriptor for archive
  65. X *      af_readdata -- read data from archive
  66. X *    af_readattrs -- read attributes from archive
  67. X *    af_writearchive -- write it
  68. X */
  69. X
  70. X#include <stdio.h>
  71. X#include <string.h>
  72. X#ifdef SUNOS_4_0
  73. X#include <strings.h>
  74. X#endif
  75. X#include <sys/types.h>
  76. X#include <sys/stat.h>
  77. X
  78. X#include "typeconv.h"
  79. X#include "afsys.h"
  80. X#include "afs.h"
  81. X#include "afarchive.h"
  82. X
  83. X#ifdef MEMDEBUG
  84. Xextern FILE *memprot;
  85. X#endif
  86. X
  87. Xint     af_fhash();
  88. XUid_t   getuid();
  89. X
  90. X/*==========================================================================
  91. X * List of list-descriptors + hash table for faster access
  92. X *
  93. X * Allocated memory will never be freed up to now
  94. X *
  95. X *==========================================================================*/
  96. X
  97. X/* these two pointers should be local -- EXPORT only for debugging */
  98. XLOCAL Af_revlist lst;
  99. XEXPORT Af_revlist *af_lists = (Af_revlist *)0;  
  100. X                                    /* base address of all list descriptors */
  101. X
  102. XEXPORT Af_revlist *af_freelist = &lst;  /* beginning of freelist */
  103. X
  104. XLOCAL Af_hash af_arhash;
  105. Xbool  hinit = FALSE; /* indicate if hashtable is yet initialized */
  106. X
  107. X/*======================== init_ldes =======================================*/
  108. X
  109. XLOCAL Af_revlist *init_ldes (path, name, type)
  110. X     char *path, *name, *type;
  111. X{
  112. X  register   i;
  113. X  Af_revlist *list, *oldlist, **oldptr, *tail;
  114. X  char       hashsymbol[MAXNAMLEN], *malloc(), *pathsym;
  115. X
  116. X  oldptr = &oldlist;
  117. X  /* init hashtable if it is not yet done */
  118. X  if (!hinit)
  119. X    {
  120. X      (void) af_hashinit (&af_arhash, AF_MAXLISTS, af_fhash);
  121. X      hinit = TRUE;
  122. X    }
  123. X
  124. X  pathsym = af_entersym (path);
  125. X
  126. X  (void) strcpy (hashsymbol, name);
  127. X  if (type)
  128. X    if (type[0])
  129. X      {
  130. X    (void) strcat (hashsymbol, ".");
  131. X    (void) strcat (hashsymbol, type);
  132. X      }
  133. X    
  134. X  /* if there are open archives check if desired archive is loaded yet */
  135. X  if (af_lists != (Af_revlist *)0)
  136. X    {
  137. X      if (af_symlookup (&af_arhash, hashsymbol, (Af_revlist *)0, oldptr))
  138. X    {
  139. X      /* found something */
  140. X      /* if it is the right list */
  141. X      if (oldlist->af_cattrs.af_syspath == pathsym)
  142. X        return (oldlist);
  143. X      /* else continue the search as long as there are entries */
  144. X      while (af_symlookup (&af_arhash, hashsymbol, oldlist, oldptr))
  145. X        {
  146. X          if (oldlist->af_cattrs.af_syspath == pathsym)
  147. X        return (oldlist);
  148. X        }
  149. X    }
  150. X    }
  151. X
  152. X  /* if there are no more descriptors available - allocate new space */
  153. X  if (af_freelist == (Af_revlist *)0)
  154. X    {
  155. X      if ((af_freelist = (Af_revlist *) malloc ((unsigned) (AF_LISTSEG * sizeof (Af_revlist)))) == (Af_revlist *)0)
  156. X    FAIL ("readattrs", "malloc(i)", AF_ESYSERR, (Af_revlist *)0);
  157. X
  158. X      /* build up new freelist */
  159. X      for (i=1; i<AF_LISTSEG; i++)
  160. X    af_freelist[i-1].af_next = &(af_freelist[i]);
  161. X      af_freelist[AF_LISTSEG-1].af_next = (Af_revlist *)0;
  162. X    }
  163. X
  164. X  if (af_lists != (Af_revlist *)0)
  165. X    {
  166. X      tail = af_lists->af_next;
  167. X      af_lists->af_next = af_freelist;
  168. X      af_freelist = af_freelist->af_next;
  169. X      list = af_lists->af_next;
  170. X      bzero ((char *)list, sizeof (*list));
  171. X
  172. X      list->af_next = tail;
  173. X    }
  174. X  else
  175. X    {
  176. X      list = af_freelist;
  177. X      af_freelist = af_freelist->af_next;
  178. X      /* initialize whole struct (i.e. set af_next to "nil") */
  179. X      bzero ((char *)list, sizeof (*list));
  180. X      af_lists = list;
  181. X    }
  182. X
  183. X  list->af_mem = (char *)0;
  184. X  list->af_cattrs.af_host = af_gethostname ();
  185. X  list->af_cattrs.af_syspath = pathsym;
  186. X  list->af_lastmod = (time_t) 0;
  187. X
  188. X  /* add list to hashtable */
  189. X  (void) af_hashsym (&af_arhash, hashsymbol, list);
  190. X#ifdef MEMDEBUG
  191. X  fprintf (memprot, "InitArch (%s)\n", hashsymbol);
  192. X#endif
  193. X
  194. X  return (list);
  195. X}
  196. X
  197. X
  198. X/*==========================================================================
  199. X *    af_detarchive -- free descriptor for archive
  200. X *
  201. X *
  202. X *==========================================================================*/
  203. X
  204. XEXPORT af_detarchive (archive)
  205. X     Af_revlist *archive;
  206. X{
  207. X  register int i;
  208. X  Af_revlist *list;
  209. X  char hashsymbol[MAXNAMLEN], *type;
  210. X
  211. X  /* if first list descriptor should be deleted - the base (af_lists) */
  212. X  /* has to be preserved */
  213. X  if (archive == af_lists)
  214. X    af_lists = af_lists->af_next;
  215. X  else
  216. X    {
  217. X      /* if archive list has more than one entry -- close gap in list */
  218. X      if ((list = af_lists) != (Af_revlist *)0)
  219. X    {
  220. X      while (list->af_next != archive)
  221. X        if ((list = list->af_next) == (Af_revlist *)0)
  222. X          FAIL ("detarchive", "archive lost", AF_EINTERNAL, ERROR);
  223. X      list->af_next = archive->af_next;
  224. X    }
  225. X    }
  226. X
  227. X  /* remove list from hash table */
  228. X  type = af_aftype (archive->af_arfilename);
  229. X  (void) strcpy (hashsymbol, af_afname (archive->af_arfilename));
  230. X  if (type)
  231. X    if (type[0])
  232. X      {
  233. X    (void) strcat (hashsymbol, ".");
  234. X    (void) strcat (hashsymbol, type);
  235. X      }
  236. X  (void) af_delsym (&af_arhash, hashsymbol, archive);
  237. X
  238. X  /* hang free entry at the beginning of freelist */
  239. X  archive->af_next = af_freelist;
  240. X  af_freelist = archive;
  241. X
  242. X  /* free all allocated memory */
  243. X  for (i=0; i<archive->af_listlen; i++)
  244. X    {
  245. X      if (archive->af_list[i].af_class & AF_VALID)
  246. X    af_hashfree (&(archive->af_list[i].af_uhtab));
  247. X    }
  248. X  af_frmemlist (archive);
  249. X
  250. X  return (AF_OK);
  251. X}
  252. X
  253. X/*==========================================================================
  254. X *    firstitem, nextitem -- isolate items in input line
  255. X *==========================================================================*/
  256. X
  257. XLOCAL char *firstitem (line)
  258. X     char *line;
  259. X{
  260. X  char *sptr;
  261. X
  262. X  /* skip leading blank */
  263. X  if ((sptr = index (&line[1], ' ')) == (char *)0)
  264. X    sptr = index (&line[1], '\n');
  265. X
  266. X  *sptr = '\0';
  267. X  return (&line[1]);
  268. X}
  269. X
  270. XLOCAL char *nextitem (line)
  271. X     char *line;
  272. X{
  273. X  char *sptr, *finptr;
  274. X
  275. X  sptr = &line[strlen(line)]+1; /* move to next entry */
  276. X  if ((finptr = index (sptr, ' ')) == (char *)0)
  277. X    finptr = index (sptr, '\n');
  278. X  *finptr = '\0';
  279. X
  280. X  return (sptr);
  281. X}
  282. X  
  283. X/*======================= rddata ====================================*/
  284. X
  285. XLOCAL af_rddata (file, dbuf, list)
  286. X     FILE   *file;
  287. X     char   *dbuf;
  288. X     Af_revlist *list;
  289. X{
  290. X  char    idstr[AF_IDSTRLEN+1], *itemptr, line[AF_LINESIZ];
  291. X  int   i, gen, rev, maxindex;
  292. X  off_t    size, dpos = 0;
  293. X
  294. X  /* if there is a valid busy version */
  295. X  if (list->af_list[0].af_class & AF_VALID)
  296. X    maxindex = list->af_nrevs;
  297. X  else
  298. X    maxindex = list->af_nrevs+1;
  299. X
  300. X  idstr[AF_IDSTRLEN] = '\0';
  301. X  /* skip busy version */
  302. X  for (i=1; i < maxindex; i++)
  303. X    {
  304. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  305. X      if (strcmp (idstr, AF_NOTEID))
  306. X    FAIL ("rddata", "wrong note-ID in datafile", AF_EINCONSIST, ERROR);
  307. X      (void) fgets (line, AF_LINESIZ, file);
  308. X      itemptr = firstitem (line);
  309. X      gen = atoi (itemptr);
  310. X      itemptr = nextitem (itemptr);
  311. X      rev = atoi (itemptr);
  312. X      itemptr = nextitem (itemptr);
  313. X      size = (off_t) atoi (itemptr);
  314. X
  315. X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
  316. X    FAIL ("rddata", "wrong version in datafile", AF_EINCONSIST, ERROR);
  317. X
  318. X      /* read note */
  319. X      (void) fread (&(dbuf[dpos]), sizeof(char), (Size_t) size, file);
  320. X      list->af_list[i].af_notesize = size;
  321. X      list->af_list[i].af_note = &(dbuf[dpos]);
  322. X      /* replace newline by nullbyte */
  323. X      list->af_list[i].af_note[size-sizeof(char)] = '\0';
  324. X      dpos = dpos+size;
  325. X
  326. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  327. X      if (strcmp (idstr, AF_DATAID))
  328. X    FAIL ("rddata", "wrong data-ID in datafile", AF_EINCONSIST, ERROR);
  329. X      (void) fgets (line, AF_LINESIZ, file);
  330. X      itemptr = firstitem (line);
  331. X      gen = atoi (itemptr);
  332. X      itemptr = nextitem (itemptr);
  333. X      rev = atoi (itemptr);
  334. X      itemptr = nextitem (itemptr);
  335. X      itemptr = nextitem (itemptr);
  336. X      size = (off_t) atoi (itemptr);
  337. X
  338. X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
  339. X    FAIL ("rddata", "wrong version in datafile", AF_EINCONSIST, ERROR);
  340. X
  341. X      /* read data */
  342. X      (void) fread (&(dbuf[dpos]), sizeof(char), (Size_t) size, file);
  343. X      list->af_list[i].af_data = &(dbuf[dpos]);
  344. X      dpos = dpos+size;
  345. X    }
  346. X  return (AF_OK);
  347. X} /* af_rddata */
  348. X
  349. X/*==========================================================================
  350. X *    af_readdata -- read notes and data section of archive file
  351. X *
  352. X *
  353. X *==========================================================================*/
  354. X
  355. XEXPORT af_readdata (list)
  356. X     Af_revlist *list;
  357. X{
  358. X  char *data, idstr[AF_SEGSTRLEN+1], archname[MAXNAMLEN], line[AF_LINESIZ];
  359. X  FILE *archfile;
  360. X  short version;
  361. X
  362. X  /* if notes are already loaded */
  363. X  if ((list->af_extent & AF_DATA) == AF_DATA)
  364. X    return (AF_OK);
  365. X
  366. X  (void) strcpy (archname, list->af_arfilename);
  367. X  archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
  368. X  if ((archfile = fopen (archname, "r")) == (FILE *)0)
  369. X    FAIL ("readdata", "", AF_ENOAFSFILE, ERROR);
  370. X
  371. X  idstr[AF_SEGSTRLEN] = '\0';
  372. X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
  373. X  if (strncmp (idstr, AF_DATAHEADER, AF_SEGSTRLEN))
  374. X    FAIL ("readdata", "wrong header in datafile", AF_EINCONSIST, ERROR);
  375. X
  376. X  (void) fgets (line, AF_LINESIZ, archfile);
  377. X  version = atoi (line);
  378. X  if (version != AF_ARCURVERS)
  379. X    FAIL ("readdata", "unknown archive format version", AF_EINCONSIST, ERROR);
  380. X
  381. X  /* allocate memory for data */
  382. X  if ((data = af_malloc (list, (unsigned) list->af_datasize)) == (char *)0)
  383. X    FAIL ("readdata", "malloc", AF_ESYSERR, ERROR);
  384. X
  385. X  if (af_rddata (archfile, data, list) != AF_OK)
  386. X    return (ERROR);
  387. X
  388. X  list->af_extent |= AF_DATA;
  389. X  (void) fclose (archfile);
  390. X  return (AF_OK);
  391. X}
  392. X
  393. X/*======================= rdattrs ====================================*/
  394. X
  395. XLOCAL af_rdattrs (file, list, bibufptr)
  396. X     FILE     *file;
  397. X     Af_revlist  *list;
  398. X     struct stat *bibufptr;
  399. X{
  400. X  char idstr[AF_IDSTRLEN+1], *itemptr, line[AF_LINESIZ];
  401. X  int  i;
  402. X  bool writeok;
  403. X  Af_user *user, *owner, *af_garown();
  404. X
  405. X  /* skip idstring */
  406. X  idstr[AF_IDSTRLEN] = '\0';
  407. X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
  408. X  
  409. X  /* read constant attributes and variant of busy version */
  410. X  (void) fgets (line, AF_LINESIZ, file);
  411. X
  412. X  /* check location (only host is checked up to now) */
  413. X  /* path, name and type could be checked too */
  414. X
  415. X  itemptr = firstitem (line); /* host */
  416. X  if (strcmp (list->af_cattrs.af_host, itemptr))
  417. X    {
  418. X      /* FAIL ("rdattrs", "", AF_ELOC, ERROR); -- replaced by: */
  419. X      af_wng ("readattrs", "wrong hostname in archive file");
  420. X      list->af_cattrs.af_host = af_entersym (itemptr);
  421. X    }
  422. X  itemptr = nextitem (itemptr); /* path - skipped ... */
  423. X  itemptr = nextitem (itemptr); /* name - skipped ... */
  424. X  itemptr = nextitem (itemptr); /* type - skipped ... */
  425. X
  426. X  itemptr = nextitem (itemptr); /* variant */
  427. X  if (strcmp (itemptr, AF_NOSTRING))
  428. X    list->af_list[0].af_variant = af_entersym (itemptr);
  429. X  else
  430. X    list->af_list[0].af_variant = (char *)0;
  431. X
  432. X  /* get owner of archive directory */
  433. X  if ((owner = af_garown (list->af_arfilename, &writeok)) == (Af_user *)0)
  434. X    FAIL ("rdattrs", "cannot get owner of archive", AF_EINTERNAL, ERROR);
  435. X  list->af_cattrs.af_ownname = af_entersym (owner->af_username);
  436. X  list->af_cattrs.af_ownhost = af_enterhost (owner->af_userhost);
  437. X
  438. X  if (writeok)
  439. X    list->af_extent |= AF_UXWRITE;
  440. X  
  441. X  /* read owner from archive */
  442. X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
  443. X  (void) fgets (line, AF_LINESIZ, file); /* name and host of owner */
  444. X  /* plausibility of owner should be checked here */
  445. X
  446. X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
  447. X  (void) fgets (line, AF_LINESIZ, file); /* predecessor of busy object */
  448. X  itemptr = firstitem (line);
  449. X  list->af_list[0].af_predgen = atoi (itemptr);
  450. X  itemptr = nextitem (itemptr);
  451. X  list->af_list[0].af_predrev = atoi (itemptr);
  452. X
  453. X  (void) fgets (idstr, AF_IDSTRLEN+1, file);
  454. X  (void) fgets (line, AF_LINESIZ, file); /* locker */
  455. X  itemptr = firstitem (line);
  456. X  if (strcmp (itemptr, AF_NOSTRING))
  457. X    {
  458. X      list->af_list[0].af_lckname = af_entersym (itemptr);
  459. X      itemptr = nextitem (itemptr);
  460. X      list->af_list[0].af_lckhost = af_enterhost (itemptr);
  461. X    }
  462. X  else
  463. X    {
  464. X      list->af_list[0].af_lckname = (char *)0;
  465. X      itemptr = nextitem (itemptr);
  466. X      list->af_list[0].af_lckhost = (char *)0;
  467. X    }
  468. X  itemptr = nextitem (itemptr);
  469. X  list->af_list[0].af_ltime = (time_t)atoi(itemptr);
  470. X
  471. X  /* initialize and attributes for busy version */
  472. X  list->af_list[0].af_gen = AF_BUSYVERS;
  473. X  list->af_list[0].af_rev = AF_BUSYVERS;
  474. X  list->af_list[0].af_state = AF_BUSY;
  475. X  list->af_list[0].af_stime = AF_NOTIME;
  476. X  list->af_list[0].af_udanum = 0;
  477. X  list->af_list[0].af_repr = AF_FILE;
  478. X  list->af_list[0].af_dsize = (off_t) 0;
  479. X  list->af_list[0].af_data = (char *)0;
  480. X  list->af_list[0].af_hashname = (char *)0;
  481. X  list->af_list[0].af_nlinks = 0;
  482. X  list->af_list[0].af_succgen = AF_NOVNUM;
  483. X  list->af_list[0].af_succrev = AF_NOVNUM;
  484. X
  485. X  if (bibufptr->st_ino) /* if there is a busy version */
  486. X    {
  487. X      list->af_list[0].af_class = AF_VALID;
  488. X      if ((user = af_getuser (bibufptr->st_uid)) == (Af_user *)0)
  489. X    {
  490. X      af_wng ("rdattrs", "invalid userID in inode of busy file");
  491. X      user = af_getuser (getuid());
  492. X    }
  493. X      list->af_list[0].af_auname = af_entersym (user->af_username);
  494. X      list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
  495. X      list->af_list[0].af_mode = (u_short) bibufptr->st_mode;
  496. X      list->af_list[0].af_mtime = (time_t) af_cvttime (bibufptr->st_mtime);
  497. X      list->af_list[0].af_atime = (time_t) af_cvttime (bibufptr->st_atime);
  498. X      list->af_list[0].af_ctime = (time_t) af_cvttime (bibufptr->st_ctime);
  499. X      list->af_list[0].af_fsize = (off_t) bibufptr->st_size;
  500. X    }
  501. X  else
  502. X    {
  503. X      list->af_list[0].af_class = 0;
  504. X      list->af_list[0].af_auname = (char *)0;
  505. X      list->af_list[0].af_auhost = (char *)0;
  506. X      list->af_list[0].af_mode = AF_NOMODE;
  507. X      list->af_list[0].af_mtime = AF_NOTIME;
  508. X      list->af_list[0].af_atime = AF_NOTIME;
  509. X      list->af_list[0].af_ctime = AF_NOTIME;
  510. X      list->af_list[0].af_fsize = AF_NOTIME;
  511. X    }
  512. X      
  513. X  /* read list */
  514. X  for (i=1; i < list->af_nrevs; i++)
  515. X    {
  516. X      /* do initializations */
  517. X      list->af_list[i].af_class = AF_VALID;
  518. X      list->af_list[i].af_notesize = 0;
  519. X      list->af_list[i].af_note = (char *)0;
  520. X      list->af_list[i].af_data = (char *)0;
  521. X      list->af_list[i].af_nlinks = 0;
  522. X      list->af_list[i].af_hashname = (char *)0;
  523. X
  524. X      /* enter name (set a pointer to the name-field of af_list[0]) */
  525. X      /* skip position 0 */
  526. X      if (i != 0)
  527. X    {
  528. X      list->af_list[i].af_name = list->af_list[0].af_name;
  529. X      list->af_list[i].af_type = list->af_list[0].af_type;
  530. X    }
  531. X
  532. X      /* read revision ID */
  533. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  534. X      if (strcmp (idstr, AF_REVID)) /* could be done for every field */
  535. X    FAIL ("rdattrs", 
  536. X          "wrong revision-ID in archive file", AF_EINCONSIST, ERROR);
  537. X      (void) fgets (line, AF_LINESIZ, file);
  538. X      itemptr = firstitem (line);
  539. X      list->af_list[i].af_gen = atoi (itemptr);
  540. X      itemptr = nextitem (itemptr);
  541. X      list->af_list[i].af_rev = atoi (itemptr);
  542. X      itemptr = nextitem (itemptr);
  543. X      list->af_list[i].af_state = (short) atoi (itemptr);
  544. X      itemptr = nextitem (itemptr);
  545. X      (void) sscanf (itemptr, "%ho", &(list->af_list[i].af_mode));
  546. X      itemptr = nextitem (itemptr);
  547. X      if (strcmp (itemptr, AF_NOSTRING))
  548. X    list->af_list[i].af_variant = af_entersym (itemptr);
  549. X      else
  550. X    list->af_list[i].af_variant = (char *)0;
  551. X      
  552. X      /* read author*/
  553. X      (void) fgetc (file); /* skip tab */
  554. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  555. X      (void) fgets (line, AF_LINESIZ, file); /* predecessor of busy object */
  556. X      itemptr = firstitem (line);
  557. X      list->af_list[i].af_auname = af_entersym (itemptr);
  558. X      itemptr = nextitem (itemptr);
  559. X      list->af_list[i].af_auhost = af_enterhost (itemptr);
  560. X      itemptr = nextitem (itemptr);
  561. X      if (strcmp (itemptr, AF_NOSTRING))
  562. X          {
  563. X      list->af_list[i].af_lckname = af_entersym (itemptr);
  564. X      itemptr = nextitem (itemptr);
  565. X      list->af_list[i].af_lckhost = af_enterhost (itemptr);
  566. X    }
  567. X      else
  568. X    {
  569. X      list->af_list[i].af_lckname = (char *)0;
  570. X      itemptr = nextitem (itemptr);
  571. X      list->af_list[i].af_lckhost = (char *)0;
  572. X    }
  573. X
  574. X      /* read dates */
  575. X      (void) fgetc (file); /* skip tab */
  576. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  577. X      (void) fgets (line, AF_LINESIZ, file);
  578. X      itemptr = firstitem (line);
  579. X      list->af_list[i].af_mtime = (time_t) atoi (itemptr);
  580. X      itemptr = nextitem (itemptr);
  581. X      list->af_list[i].af_atime = (time_t) atoi (itemptr);
  582. X      itemptr = nextitem (itemptr);
  583. X      list->af_list[i].af_ctime = (time_t) atoi (itemptr);
  584. X      itemptr = nextitem (itemptr);
  585. X      list->af_list[i].af_stime = (time_t) atoi (itemptr);
  586. X      itemptr = nextitem (itemptr);
  587. X      list->af_list[i].af_ltime = (time_t) atoi (itemptr);
  588. X
  589. X      /* read kind of representation */
  590. X      (void) fgetc (file); /* skip tab */
  591. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  592. X      (void) fgets (line, AF_LINESIZ, file);
  593. X      itemptr = firstitem (line);
  594. X      list->af_list[i].af_repr = (short) atoi (itemptr);
  595. X      itemptr = nextitem (itemptr);
  596. X      list->af_list[i].af_fsize = (off_t) atoi (itemptr);
  597. X      itemptr = nextitem (itemptr);
  598. X      list->af_list[i].af_dsize = (off_t) atoi (itemptr);
  599. X      itemptr = nextitem (itemptr);
  600. X      list->af_list[i].af_succgen = atoi (itemptr);
  601. X      itemptr = nextitem (itemptr);
  602. X      list->af_list[i].af_succrev = atoi (itemptr);
  603. X      itemptr = nextitem (itemptr);
  604. X      list->af_list[i].af_predgen = atoi (itemptr);
  605. X      itemptr = nextitem (itemptr);
  606. X      list->af_list[i].af_predrev = atoi (itemptr);
  607. X    }
  608. X  if (!(bibufptr->st_ino)) /* if there is no busy version */
  609. X    list->af_nrevs--;
  610. X  
  611. X  return (AF_OK);
  612. X} /* af_rdattrs */
  613. X
  614. X/*======================= rdudas ====================================*/
  615. X
  616. X#define AF_UDASEGSIZ 8
  617. X
  618. XLOCAL af_rdudas (file, list)
  619. X     FILE       *file;
  620. X     Af_revlist *list;
  621. X{
  622. X  char    idstr[AF_IDSTRLEN+1], *udabuf, *malloc(), *realloc();
  623. X  char  *itemptr, line[AF_LINESIZ];
  624. X  int    c, i, j, gen, rev, maxindex;
  625. X
  626. X  /* if there is a valid busy version */
  627. X  if (list->af_list[0].af_class & AF_VALID)
  628. X    maxindex = list->af_nrevs;
  629. X  else
  630. X    maxindex = list->af_nrevs+1;
  631. X
  632. X  (void) getc (file); /* skip newline */
  633. X  idstr[AF_IDSTRLEN] = '\0';
  634. X  for (i=0; i < maxindex; i++)
  635. X    {
  636. X      (void) fgets (idstr, AF_IDSTRLEN+1, file);
  637. X      if (strcmp (idstr, AF_UDAID))
  638. X    FAIL ("rdudas", "wrong uda-ID in archive file", AF_EINCONSIST, ERROR);
  639. X      (void) fgets (line, AF_LINESIZ, file);
  640. X      itemptr = firstitem (line);
  641. X      gen = atoi (itemptr);
  642. X      itemptr = nextitem (itemptr);
  643. X      rev = atoi (itemptr);
  644. X
  645. X      if ((list->af_list[i].af_gen != gen) || (list->af_list[i].af_rev != rev))
  646. X    FAIL ("rdudas", "wrong version in archive file", AF_EINCONSIST, ERROR);
  647. X      
  648. X      /* build up hashlist and read user define attributes */
  649. X      if (af_hashinit (&list->af_list[i].af_uhtab, AF_MAXUDAS, af_fhash)
  650. X                                                             == ERROR)
  651. X    return (ERROR);
  652. X
  653. X      if (i == 0) /* initalize only once */
  654. X    {
  655. X      if ((udabuf = malloc ((unsigned) (AF_UDASEGSIZ * sizeof (char)))) == (char *)0)
  656. X        FAIL ("rdudas", "malloc", AF_ESYSERR, ERROR);
  657. X    }
  658. X
  659. X      /* if there is *no* valid busy version, skip the user defined */
  660. X      /* attributes for the busy version */
  661. X      if ((i==0) && !(list->af_list[0].af_class & AF_VALID))
  662. X    {
  663. X      while (TRUE)
  664. X        {
  665. X          if ((c = getc (file)) == '\0')
  666. X        {
  667. X          if ((c = getc (file)) == '\0')
  668. X            break;
  669. X        }
  670. X        }
  671. X      (void) getc (file); /* skip trailing newline char */
  672. X      continue;
  673. X    }
  674. X
  675. X      j = 0;
  676. X      while (TRUE)
  677. X    {
  678. X      if ((udabuf[j] = getc (file)) == '\0')
  679. X        { 
  680. X          if (j != 0)
  681. X        {
  682. X          (void) af_hashsym (&list->af_list[i].af_uhtab, udabuf, (Af_revlist *)0);
  683. X#ifdef MEMDEBUG
  684. X          fprintf (memprot, "Uda (%s)\n", udabuf);
  685. X#endif
  686. X          list->af_list[i].af_udanum++;
  687. X        }
  688. X          /* a second nullbyte indicates the end of the list of udas */
  689. X          if ((c = getc (file)) == '\0')
  690. X        break;
  691. X          udabuf[0] = c;
  692. X          j = 1;
  693. X        }
  694. X      else
  695. X        {
  696. X          j++;
  697. X          if ((j % AF_UDASEGSIZ) == 0) /* if segment is full */
  698. X        {
  699. X          if ((udabuf = realloc (udabuf, (unsigned) ((j + AF_UDASEGSIZ) * sizeof (char)))) == (char *)0) 
  700. X            FAIL ("rdudas", "realloc", AF_ESYSERR, ERROR);
  701. X        }
  702. X        }
  703. X    }
  704. X      (void) getc (file); /* skip trailing newline char */
  705. X    }
  706. X  free (udabuf);
  707. X  return (AF_OK);
  708. X} /* af_rdudas */
  709. X
  710. X/*==========================================================================
  711. X *    af_readattrs -- read attributes from archive file
  712. X *                      
  713. X *
  714. X *==========================================================================*/
  715. X
  716. XEXPORT Af_revlist *af_readattrs (path, name, type, mode)
  717. X     char *path, *name, *type;
  718. X     bool *mode;
  719. X{
  720. X  char      idstr[AF_SEGSTRLEN+1], line[AF_LINESIZ], *itemptr;
  721. X  FILE      *archfile;
  722. X  struct stat bibuf, aibuf;
  723. X  Af_revlist *list, *init_ldes();
  724. X  short   version;
  725. X  bool    writeok;
  726. X  Af_user *user, *owner, *af_garown();
  727. X
  728. X  if ((list = init_ldes (path, name, type)) == (Af_revlist *)0)
  729. X    return ((Af_revlist *)0);
  730. X
  731. X  /* if attributes are already loaded */
  732. X  if ((list->af_extent & AF_ATTRS) == AF_ATTRS)
  733. X    {
  734. X      if (*mode == FALSE)
  735. X    {
  736. X      /* see if busy version has changed */
  737. X      if (lstat (list->af_busyfilename, &bibuf) == ERROR)
  738. X        bibuf.st_ctime = AF_NOTIME;
  739. X      if (bibuf.st_ctime != list->af_list[0].af_ctime)
  740. X        {
  741. X          /* update busy version */
  742. X          if (!(list->af_list[0].af_class & AF_VALID))
  743. X        {
  744. X          list->af_nrevs++;
  745. X          if (af_hashinit (&list->af_list[0].af_uhtab,
  746. X                   AF_MAXUDAS, af_fhash) == ERROR)
  747. X            return ((Af_revlist *)0);
  748. X          list->af_list[0].af_class = AF_VALID;
  749. X        }
  750. X          if ((user = af_getuser (bibuf.st_uid)) == (Af_user *)0)
  751. X        {
  752. X          af_wng ("readattrs", "invalid userID in inode of busy file");
  753. X          user = af_getuser (getuid());
  754. X        }
  755. X          list->af_list[0].af_auname = af_entersym (user->af_username);
  756. X          list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
  757. X          list->af_list[0].af_mode = (u_short) bibuf.st_mode;
  758. X          list->af_list[0].af_mtime = (time_t) af_cvttime (bibuf.st_mtime);
  759. X          list->af_list[0].af_atime = (time_t) af_cvttime (bibuf.st_atime);
  760. X          list->af_list[0].af_ctime = (time_t) af_cvttime (bibuf.st_ctime);
  761. X          list->af_list[0].af_fsize = (off_t) bibuf.st_size;
  762. X        }
  763. X    }
  764. X      *mode = TRUE;
  765. X      return (list);
  766. X    }
  767. X  else
  768. X    {
  769. X      *mode = FALSE;
  770. X    }
  771. X
  772. X  if ((list->af_busyfilename = af_gbusname (list->af_cattrs.af_syspath,
  773. X                         name, type)) == (char *)0)
  774. X    return ((Af_revlist *)0);
  775. X  
  776. X  list->af_arfilename = af_garname (list->af_cattrs.af_syspath, name, type);
  777. X  list->af_extent |= AF_ARCHIVE;
  778. X
  779. X  if (lstat (list->af_busyfilename, &bibuf) == ERROR)
  780. X    bibuf.st_ino = 0;
  781. X
  782. X  /* open archive */
  783. X  if ((list->af_arfilename == (char *)0) ||
  784. X      ((archfile = fopen (list->af_arfilename, "r")) == (FILE *)0))
  785. X    {
  786. X      if (bibuf.st_ino == 0) /* no busy file */
  787. X    {
  788. X      (void) af_detarchive (list);
  789. X      SFAIL ("readattrs", "", AF_ENOAFSFILE, (Af_revlist *)0);
  790. X    }
  791. X      list->af_nrevs = 1;
  792. X      list->af_listlen = AF_NEWREVS;
  793. X      list->af_extent |= AF_ALLSEGS;
  794. X      list->af_datasize = 0;
  795. X
  796. X      /* determine author of busy file */
  797. X      if ((user = af_getuser (bibuf.st_uid)) == (Af_user *)0)
  798. X    {
  799. X      af_wng ("readattrs", "invalid userID in inode of busy file");
  800. X      user = af_getuser (getuid());
  801. X    }
  802. X
  803. X      /* if an archive-directory exists, get its owner */
  804. X      if ((owner = af_garown (list->af_arfilename, &writeok)) == (Af_user *)0)
  805. X    {
  806. X      list->af_cattrs.af_ownname = af_entersym (user->af_username);
  807. X      list->af_cattrs.af_ownhost = af_enterhost (user->af_userhost);
  808. X    }
  809. X      else
  810. X    {
  811. X      list->af_cattrs.af_ownname = af_entersym (owner->af_username);
  812. X      list->af_cattrs.af_ownhost = af_enterhost (owner->af_userhost);
  813. X    }
  814. X      if (writeok)
  815. X    list->af_extent |= AF_UXWRITE;
  816. X      
  817. X      if ((list->af_list = (Af_vattrs *)af_malloc (list, (unsigned) (list->af_listlen * sizeof(Af_vattrs)))) == (Af_vattrs *)0)
  818. X    FAIL ("readattrs", "malloc,1", AF_ESYSERR, (Af_revlist *)0);
  819. X      
  820. X      bzero ((char *)list->af_list, list->af_listlen * sizeof (Af_vattrs));
  821. X      /* init attrbuf for busy version  (relevant attrs only) */
  822. X      list->af_list[0].af_name = af_entersym (name);
  823. X      list->af_list[0].af_type = af_entersym (type);
  824. X      list->af_list[0].af_gen = AF_BUSYVERS;
  825. X      list->af_list[0].af_rev = AF_BUSYVERS;
  826. X      list->af_list[0].af_variant = (char *)0;
  827. X      list->af_list[0].af_state = AF_BUSY;
  828. X      list->af_list[0].af_class = AF_VALID;
  829. X      list->af_list[0].af_auname = af_entersym (user->af_username);
  830. X      list->af_list[0].af_auhost = af_enterhost (user->af_userhost);
  831. X      list->af_list[0].af_mode = (u_short) bibuf.st_mode;
  832. X      list->af_list[0].af_lckname = (char *)0;
  833. X      list->af_list[0].af_lckhost = (char *)0;
  834. X      list->af_list[0].af_mtime = (time_t) af_cvttime (bibuf.st_mtime);
  835. X      list->af_list[0].af_atime = (time_t) af_cvttime (bibuf.st_atime);
  836. X      list->af_list[0].af_ctime = (time_t) af_cvttime (bibuf.st_ctime);
  837. X      list->af_list[0].af_stime = AF_NOTIME;
  838. X      list->af_list[0].af_ltime = AF_NOTIME;
  839. X      list->af_list[0].af_notesize = 1;
  840. X      list->af_list[0].af_note = (char *)0;
  841. X      list->af_list[0].af_udanum = 0;
  842. X      if (af_hashinit (&list->af_list[0].af_uhtab, AF_MAXUDAS, af_fhash)
  843. X                                                             == ERROR)
  844. X    return ((Af_revlist *)0);
  845. X      list->af_list[0].af_repr = AF_FILE;
  846. X      list->af_list[0].af_fsize = (off_t) bibuf.st_size;
  847. X      list->af_list[0].af_dsize = 0;
  848. X      list->af_list[0].af_data = (char *)0;
  849. X      list->af_list[0].af_hashname = (char *)0;
  850. X      list->af_list[0].af_nlinks = 0;
  851. X      list->af_list[0].af_succgen = AF_NOVNUM;
  852. X      list->af_list[0].af_succrev = AF_NOVNUM;
  853. X      list->af_list[0].af_predgen = AF_NOVNUM;
  854. X      list->af_list[0].af_predrev = AF_NOVNUM;
  855. X      return (list);
  856. X    }
  857. X  
  858. X  /* record date of last modification */
  859. X  (void) lstat (list->af_arfilename, &aibuf);
  860. X  list->af_lastmod = (time_t) af_cvttime (aibuf.st_mtime);
  861. X
  862. X  /* archive file ??? */
  863. X  idstr[AF_SEGSTRLEN] = '\0';
  864. X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
  865. X  if (strncmp (idstr, AF_ARHEADER, AF_SEGSTRLEN))
  866. X    FAIL ("readattrs",
  867. X      "wrong header in archive file", AF_EINCONSIST, (Af_revlist *)0);
  868. X  
  869. X  /* read header */
  870. X  (void) fgets (line, AF_LINESIZ, archfile);
  871. X  itemptr = firstitem (line);
  872. X  version = atoi (itemptr);
  873. X  if (version != AF_ARCURVERS)
  874. X    FAIL ("readattrs", 
  875. X      "unknown archive format version", AF_EINCONSIST, (Af_revlist *)0);
  876. X  itemptr = nextitem (itemptr);
  877. X  list->af_nrevs = atoi (itemptr);
  878. X  itemptr = nextitem (itemptr);
  879. X  list->af_datasize = atoi (itemptr);
  880. X
  881. X  /* alloc memory for revision list (plus space for new revs) */
  882. X  list->af_listlen = list->af_nrevs + AF_NEWREVS;
  883. X  if ((list->af_list = (Af_vattrs *)af_malloc (list, (unsigned) (list->af_listlen * sizeof(Af_vattrs)))) == (Af_vattrs *)0)
  884. X    FAIL ("readattrs", "malloc,2", AF_ESYSERR, (Af_revlist *)0);
  885. X
  886. X  bzero ((char *) list->af_list, list->af_listlen * sizeof (Af_vattrs));
  887. X
  888. X  /* enter name and type */
  889. X  list->af_list[0].af_name = af_entersym (name);
  890. X  list->af_list[0].af_type = af_entersym (type);
  891. X
  892. X  if (af_rdattrs (archfile, list, &bibuf) != AF_OK)
  893. X    return ((Af_revlist *)0);
  894. X
  895. X  /* read id string for user defined attributes section*/
  896. X  (void) fgets (idstr, AF_SEGSTRLEN+1, archfile);
  897. X  if (strncmp (idstr, AF_UDASEG, AF_SEGSTRLEN))
  898. X    FAIL ("readattrs",
  899. X      "wrong udaseg-ID in archive file", AF_EINCONSIST, (Af_revlist *)0);
  900. X
  901. X  if (af_rdudas (archfile, list) != AF_OK)
  902. X    return ((Af_revlist *)0);
  903. X
  904. X  list->af_extent |= (AF_ATTRS | AF_COMPLETE);
  905. X  (void) fclose (archfile);
  906. X  return (list);
  907. X} /* af_readattrs */
  908. X
  909. X
  910. X/*==========================================================================
  911. X *    writearchive -- write archive file
  912. X *
  913. X *
  914. X *==========================================================================*/
  915. X
  916. XEXPORT af_writearchive (list)
  917. X     Af_revlist *list;
  918. X{
  919. X  int   i, j, maxindex;
  920. X  FILE    *tmpfile, *datafile;
  921. X  char  tmpname[MAXNAMLEN], dataname[MAXNAMLEN], *ptrlist[AF_MAXUDAS];
  922. X  char  archname[MAXNAMLEN];
  923. X  off_t    datasize;
  924. X  Af_key *busyptr, *af_gbuskey();
  925. X
  926. X  /* File locking mechanism should be inserted here */
  927. X
  928. X  /* if all revisions have been removed */
  929. X  if (list->af_nrevs == 0)
  930. X    {
  931. X      (void) af_unlink (list->af_arfilename);
  932. X      (void) strcpy (archname, list->af_arfilename);
  933. X      archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
  934. X      (void) af_unlink (archname);
  935. X      return (AF_OK);
  936. X    }
  937. X
  938. X  (void) strcpy (tmpname, list->af_arfilename); 
  939. X  tmpname[strlen(tmpname) - sizeof(char)] = AF_ARCHTMP;
  940. X  af_regtmpfile (tmpname);
  941. X  /* open tmpfile */
  942. X  if ((tmpfile = fopen (tmpname, "w")) == (FILE *)0)
  943. X    FAIL ("writearchive", "fopen", AF_ESYSERR, ERROR);
  944. X
  945. X  /* if there is no busy version - increase "nrevs" temporarily */
  946. X  busyptr = af_gbuskey (list);
  947. X  if (!(VATTR(busyptr).af_class & AF_VALID))
  948. X    list->af_nrevs++;
  949. X
  950. X  /* write header */
  951. X  fprintf (tmpfile, "%s %d %d %ld\n", AF_ARHEADER, AF_ARCURVERS,
  952. X       list->af_nrevs, list->af_datasize);
  953. X
  954. X  /* write constant attributes */
  955. X  fprintf (tmpfile, "%s %s %s %s %s %s\n", AF_NAMEID, 
  956. X       list->af_cattrs.af_host,
  957. X       list->af_cattrs.af_syspath,
  958. X       list->af_list[0].af_name,
  959. X       NOTMT (list->af_list[0].af_type),
  960. X       NOTMT (list->af_list[0].af_variant));
  961. X
  962. X  /* write owner */
  963. X  fprintf (tmpfile, "%s %s %s\n", AF_OWNID,
  964. X       list->af_cattrs.af_ownname,
  965. X       list->af_cattrs.af_ownhost);
  966. X
  967. X
  968. X  /* write predecessor and locker of busy version */
  969. X  fprintf (tmpfile, "%s %d %d\n%s %s %s %d\n", AF_PRDID,
  970. X       VATTR(busyptr).af_predgen,
  971. X       VATTR(busyptr).af_predrev, AF_LOCKID,
  972. X       NOTMT (VATTR(busyptr).af_lckname),
  973. X       NOTMT (VATTR(busyptr).af_lckhost),
  974. X       VATTR(busyptr).af_ltime);
  975. X
  976. X  /* write list of version attributes */
  977. X  maxindex = list->af_nrevs;
  978. X  for (i=1; i < maxindex; i++)
  979. X    {
  980. X      /* skip deleted versions */
  981. X      if (!(list->af_list[i].af_class & AF_VALID))
  982. X    {
  983. X      maxindex++;
  984. X      continue;
  985. X    }
  986. X
  987. X      /* write revision ID */
  988. X      fprintf (tmpfile, "%s %d %d %d %o %s\n", AF_REVID, 
  989. X           list->af_list[i].af_gen,
  990. X           list->af_list[i].af_rev,
  991. X           list->af_list[i].af_state,
  992. X           list->af_list[i].af_mode,
  993. X           NOTMT (list->af_list[i].af_variant));
  994. X
  995. X      /* write author */
  996. X      fprintf (tmpfile, "\t%s %s %s %s %s\n", AF_AUTHORID,
  997. X           list->af_list[i].af_auname,
  998. X           list->af_list[i].af_auhost,
  999. X           NOTMT (list->af_list[i].af_lckname),
  1000. X           NOTMT (list->af_list[i].af_lckhost));
  1001. X
  1002. X      /* write dates */
  1003. X      fprintf (tmpfile, "\t%s %ld %ld %ld %ld %ld\n", AF_DATEID,
  1004. X           list->af_list[i].af_mtime,
  1005. X           list->af_list[i].af_atime,
  1006. X           list->af_list[i].af_ctime,
  1007. X           list->af_list[i].af_stime,
  1008. X           list->af_list[i].af_ltime);
  1009. X
  1010. X      /* write kind of representation and tree connects */
  1011. X      fprintf (tmpfile, "\t%s %d %ld %ld %d %d %d %d\n", AF_REPRID,
  1012. X           list->af_list[i].af_repr,
  1013. X           list->af_list[i].af_fsize,
  1014. X           list->af_list[i].af_dsize,
  1015. X           list->af_list[i].af_succgen,
  1016. X           list->af_list[i].af_succrev,
  1017. X           list->af_list[i].af_predgen,
  1018. X           list->af_list[i].af_predrev);
  1019. X    }
  1020. X
  1021. X  /* write user defined attributes */
  1022. X  fprintf (tmpfile, "%s\n", AF_UDASEG);
  1023. X  maxindex = list->af_nrevs;
  1024. X  for (i=0; i < maxindex; i++)
  1025. X    {
  1026. X      /* skip deleted versions but not the busy version */
  1027. X      if (!(list->af_list[i].af_class & AF_VALID) && 
  1028. X      (list->af_list[i].af_state != AF_BUSY))
  1029. X    { maxindex++; continue;    }
  1030. X
  1031. X      fprintf (tmpfile, "%s %d %d\n", AF_UDAID,
  1032. X           list->af_list[i].af_gen,
  1033. X           list->af_list[i].af_rev);
  1034. X      (void) af_lhashsyms (&list->af_list[i].af_uhtab, ptrlist);
  1035. X      j=0;
  1036. X      while (ptrlist[j])
  1037. X    fprintf (tmpfile, "%s%c", ptrlist[j++], '\0');
  1038. X      if (j==0) /* if no user defined attribute has been written */
  1039. X    (void) putc ('\0', tmpfile);
  1040. X      (void) putc ('\0', tmpfile);
  1041. X      (void) putc ('\n', tmpfile);
  1042. X    }
  1043. X  (void) fclose (tmpfile);
  1044. X
  1045. X  /* if data have been manipulated - write data file */
  1046. X  if ((list->af_extent & AF_DATA) == AF_DATA)
  1047. X    {
  1048. X      (void) strcpy (dataname, list->af_arfilename);
  1049. X      dataname[strlen(dataname) - sizeof(char)] = AF_DATATMP;
  1050. X      af_regtmpfile (dataname);
  1051. X      /* open tmpfile for data */
  1052. X      if ((datafile = fopen (dataname, "w")) == (FILE *)0)
  1053. X    FAIL ("writearchive", "fopen", AF_ESYSERR, ERROR);
  1054. X
  1055. X      /* write notes and data */
  1056. X      fprintf (datafile, "%s %d\n", AF_DATAHEADER, AF_ARCURVERS);
  1057. X      
  1058. X      maxindex = list->af_nrevs;
  1059. X      for (i=1; i < maxindex; i++)
  1060. X    {
  1061. X      /* skip deleted versions */
  1062. X      if (!(list->af_list[i].af_class & AF_VALID))
  1063. X        { maxindex++; continue; }
  1064. X      
  1065. X      fprintf (datafile, "%s %d %d %ld\n", AF_NOTEID,
  1066. X           list->af_list[i].af_gen,
  1067. X           list->af_list[i].af_rev,
  1068. X           list->af_list[i].af_notesize);
  1069. X      (void) fwrite (list->af_list[i].af_note, sizeof(char), (Size_t) list->af_list[i].af_notesize - sizeof(char), datafile);
  1070. X      (void) putc ('\n', datafile);
  1071. X
  1072. X      if (list->af_list[i].af_repr == AF_CHUNK)
  1073. X        datasize = list->af_list[i].af_fsize;
  1074. X      else datasize = list->af_list[i].af_dsize;
  1075. X      fprintf (datafile, "%s %d %d %d %ld\n", AF_DATAID,
  1076. X           list->af_list[i].af_gen,
  1077. X           list->af_list[i].af_rev,
  1078. X           list->af_list[i].af_repr, datasize);
  1079. X
  1080. X      (void) fwrite (list->af_list[i].af_data, sizeof(char), (Size_t) datasize, datafile);
  1081. X    }
  1082. X      (void) fclose (datafile);
  1083. X    }
  1084. X
  1085. X  af_unregtmpfile (tmpname);
  1086. X  (void) af_unlink (list->af_arfilename);
  1087. X  if (af_syslink (tmpname, list->af_arfilename) == ERROR)
  1088. X    FAIL ("writearchive", "link", AF_ESYSERR, ERROR);
  1089. X
  1090. X  (void) af_uchmod (list->af_arfilename, AF_ARCHMODE);
  1091. X  (void) af_unlink (tmpname);
  1092. X
  1093. X  /* if the data file has been written */
  1094. X  if ((list->af_extent & AF_DATA) == AF_DATA)
  1095. X    {
  1096. X      (void) strcpy (archname, list->af_arfilename);
  1097. X      archname[strlen(archname)-sizeof(char)] = AF_DATAEXT;
  1098. X      af_unregtmpfile (dataname);
  1099. X      (void) af_unlink (archname);
  1100. X      if (af_syslink (dataname, archname) == ERROR)
  1101. X    FAIL ("writearchive", "link", AF_ESYSERR, ERROR);
  1102. X      (void) af_uchmod (archname, AF_ARCHMODE);
  1103. X      (void) af_unlink (dataname);
  1104. X    }
  1105. X
  1106. X  /* decrease "nrevs" again (see beginning of procedure */
  1107. X  if (!(VATTR(busyptr).af_class & AF_VALID))
  1108. X    list->af_nrevs--;
  1109. X  
  1110. X  return (AF_OK);
  1111. X} /* af_writearchive */
  1112. X
  1113. END_OF_FILE
  1114. if test 35334 -ne `wc -c <'src/afs/afarchive.c'`; then
  1115.     echo shar: \"'src/afs/afarchive.c'\" unpacked with wrong size!
  1116. fi
  1117. # end of 'src/afs/afarchive.c'
  1118. fi
  1119. echo shar: End of archive 29 \(of 33\).
  1120. cp /dev/null ark29isdone
  1121. MISSING=""
  1122. 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
  1123.     if test ! -f ark${I}isdone ; then
  1124.     MISSING="${MISSING} ${I}"
  1125.     fi
  1126. done
  1127. if test "${MISSING}" = "" ; then
  1128.     echo You have unpacked all 33 archives.
  1129.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1130. else
  1131.     echo You still need to unpack the following archives:
  1132.     echo "        " ${MISSING}
  1133. fi
  1134. ##  End of shell archive.
  1135. exit 0
  1136.