source: trunk/athena/bin/discuss/server/core.c @ 22404

Revision 22404, 37.2 KB checked in by ghudson, 19 years ago (diff)
Eliminate declarations of system functions which cause warnings or errors. Fix some broken ss library calls.
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *
10 *      $Id: core.c,v 1.42 2006-03-10 07:11:40 ghudson Exp $
11 *
12 *
13 * core.c --    Routines that are the meat of discuss.  These provide user
14 *              callable routines.
15 *
16 */
17#ifndef lint
18static char rcsid_core_c[] =
19    "$Id: core.c,v 1.42 2006-03-10 07:11:40 ghudson Exp $";
20#endif /* lint */
21
22
23/* Derived from CORE.PAS 06/21/86 by SRZ */
24
25#include <discuss/types.h>
26#include <discuss/dsc_et.h>
27#include <discuss/interface.h>
28#include "mtg.h"
29#include <discuss/tfile.h>
30#include "atom.h"
31#include <discuss/acl.h>
32#include "internal.h"
33#include <errno.h>
34#include <sys/types.h>
35#include <sys/file.h>
36#include <sys/stat.h>
37#include <sys/param.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#if HAVE_FCNTL_H
42#include <fcntl.h>
43#endif
44#include <unistd.h>
45
46#ifndef min
47#define min(a, b) (a < b ? a : b)
48#endif
49extern char *new_string();
50
51extern mtg_super super;
52extern char *super_chairman;
53extern char *super_long_name;
54extern char current_mtg [];
55extern int u_trn_f,u_control_f,u_acl_f;
56extern bool nuclear;
57extern bool mtg_swapped;
58extern afile a_control_f;
59extern char rpc_caller [];
60extern int errno;
61extern int has_privs;
62extern int no_nuke;
63extern tfile abort_file;
64extern dsc_acl *mtg_acl;
65
66/*
67 *
68 * add_trn () --
69 * adds a transaction to the given meeting, either as a reply or an
70 * original transaction.  Returns an error code, and the transaction number
71 * given to the transaction
72 *
73 */
74add_trn (mtg_name, source_file, subject, reply_trn, result_trn, result)
75char *mtg_name;
76tfile source_file;
77char *subject;
78trn_nums reply_trn;             /* trn replying to;  0 if original */
79trn_nums *result_trn;           /* trn number given to added trn */
80int *result;
81{
82     add_trn_priv (mtg_name, source_file, subject, NULL, reply_trn, 0,
83                   rpc_caller, (date_times) time ((long *)0), 0,
84                   result_trn, result);
85}
86
87/*
88 *
89 * add_trn2 () --
90 * adds a transaction to the given meeting, either as a reply or an
91 * original transaction.  Returns an error code, and the transaction number
92 * given to the transaction.  Also allows a signature for the author.
93 *
94 */
95add_trn2 (mtg_name, source_file, subject, signature, reply_trn, result_trn, result)
96char *mtg_name;
97tfile source_file;
98char *subject, *signature;
99trn_nums reply_trn;             /* trn replying to;  0 if original */
100trn_nums *result_trn;           /* trn number given to added trn */
101int *result;
102{
103     add_trn_priv (mtg_name, source_file, subject, signature, reply_trn, 0,
104                   rpc_caller, (date_times) time ((long *)0), 0,
105                   result_trn, result);
106}
107
108
109/* add_trn_priv:  For those who know exactly what they want and who they are */
110
111add_trn_priv (mtg_name, source_file, subject, signature, reply_trn, desired_trn, author, date_entered, flags, result_trn, result)
112char *mtg_name;
113tfile source_file;
114char *subject;
115char *signature;
116trn_nums reply_trn;             /* trn replying to;  0 if original */
117trn_nums desired_trn;           /* trn num desired */
118char *author;
119date_times date_entered;
120int flags;
121trn_nums *result_trn;           /* trn number given to added trn */
122int *result;
123{
124     chain_blk reply_cb, cb, spare_cb;
125     int tfs,tocopy,i,len;
126     char buffer[512],*bptr,*cp;
127     trn_hdr th;
128
129/*   printf ("add_trn:  mtg %s, subject %s, reply %d\n",
130             mtg_name, subject, reply_trn); */
131     topen (source_file, "r", result);
132     if (*result) return;
133
134     abort_file = source_file;                  /* for abort's sake */
135
136     *result = open_mtg (mtg_name);
137     if (*result) { core_abort (); return; }
138
139     if (reply_trn) {
140          if (!has_mtg_access('a')) {
141               *result = NO_ACCESS;
142               core_abort (); return;
143          }
144     } else {
145          if (!has_mtg_access('w')) {
146               *result = NO_ACCESS;
147               core_abort (); return;
148          }
149     }
150
151     if (!no_nuke) {
152          a_control_f = aopen (u_control_f);
153          nuclear = TRUE;
154     }
155
156     *result = read_super ();
157     if (*result) { core_abort(); return; }
158
159     if (super.date_created == 0) {     /* Meeting has been expunged */
160          write_super();
161
162          if (!no_nuke) {
163               aclose(a_control_f);
164               nuclear = 0;
165          }
166
167          *result = open_mtg (mtg_name);
168          if (*result) { core_abort (); return; }
169
170          if (!no_nuke) {
171               a_control_f = aopen (u_control_f);
172               nuclear = TRUE;
173          }
174
175          *result = read_super ();
176          if (*result) { core_abort(); return; }
177     }   
178
179     /* check reply_trn */
180     if (reply_trn != 0) {
181          *result = read_chain (reply_trn, &reply_cb);
182          if (*result) { core_abort(); return; }
183          if (reply_cb.flags & CB_DELETED) {
184               *result = DELETED_TRN;
185               core_abort (); return;
186          }
187     }
188
189     if (desired_trn == 0 || desired_trn <= super.highest)
190          super.highest++;
191     else
192          super.highest = desired_trn;
193     
194     /* Initialize chain block */
195     cb.version = CHAIN_BLK_1;
196     cb.unique = CHAIN_BLK_UNIQUE;
197     cb.current = super.highest;
198     cb.prev = super.last;
199     cb.next = 0;
200     cb.nref = 0;
201     cb.chain_fref = 0;
202     cb.chain_lref = 0;
203     cb.flags = flags & ~CB_DELETED;
204     cb.filler = 0;
205     cb.trn_addr = fsize (u_trn_f);
206
207     if (reply_trn != 0) {                              /* info from pref */
208          cb.trn_chain = reply_cb.trn_chain;
209          read_chain (cb.trn_chain, &spare_cb);
210          cb.pref = spare_cb.chain_lref;
211     } else {
212          cb.pref = 0;                                  /* this is fref */
213          cb.trn_chain = ++super.highest_chain;
214     }
215
216     if (write_chain (&cb) != 0)                        /* write it out */
217          goto werror;
218
219     /* update fref & lref of chain */
220     read_chain (cb.trn_chain, &spare_cb);
221     spare_cb.chain_lref = cb.current;                  /* update lref */
222     if (cb.pref == 0)
223          spare_cb.chain_fref = cb.current;
224
225     if (write_chain (&spare_cb) != 0)
226          goto werror;
227
228     /* update nref of pref */
229     if (reply_trn != 0) {
230          read_chain (cb.pref, &spare_cb);
231          spare_cb.nref = cb.current;
232          write_chain (&spare_cb);
233     }
234
235     /* update next of prev */
236     if (cb.prev != 0) {
237          read_chain (cb.prev, &spare_cb);
238          spare_cb.next = cb.current;
239          write_chain (&spare_cb);
240     }
241
242     /* and finish up the super block info */
243     super.last = cb.current;
244     if (super.first == 0)
245          super.first = cb.current;
246     super.date_modified = date_entered;
247     super.high_water += sizeof (chain_blk);
248
249     if (signature != NULL && (*signature == '\0' || !strcmp(author, signature)))
250          signature = NULL;                     /* Signature is empty */
251
252     /* now write out the transaction to the trn file */
253     /* First, eliminate NL in subject */
254     cp = strchr(subject, '\n');
255     if (cp != NULL)
256          *cp = '\0';
257
258     th.version = TRN_HDR_1;
259     th.unique = TRN_HDR_UNIQUE;
260     th.current = cb.current;
261     th.orig_pref = cb.pref;
262     th.date_entered = super.date_modified;
263     th.num_lines = 0;                  /* count these later */
264     th.num_chars = tfsize (source_file);
265     th.prev_trn = super.highest_trn_addr;
266     super.highest_trn_addr = cb.trn_addr;
267     th.subject_len = strlen (subject) + 1;
268     th.author_len = strlen (author) + 1;
269     if (signature != NULL)
270          th.author_len += strlen (signature) + 1;
271     th.subject_addr = cb.trn_addr + sizeof(trn_hdr);
272     th.author_addr = th.subject_addr + th.subject_len;
273     th.text_addr = th.author_addr + th.author_len;
274
275     if (mtg_swapped)
276          swap_trn(&th);
277
278     lseek (u_trn_f, (long)0, SEEK_END);
279     if (write (u_trn_f, (char *) &th, sizeof (th)) != sizeof (th)) goto werror;
280
281     if (mtg_swapped)                                   /* Swap it back */
282          swap_trn(&th);
283
284     if (write (u_trn_f, subject, th.subject_len) != th.subject_len) goto werror;
285     if (signature == NULL) {
286          if (write (u_trn_f, author, th.author_len) != th.author_len) goto werror;
287     } else {
288          len = strlen(author)+1;
289          if (write (u_trn_f, author, len) != len) goto werror;
290          len = th.author_len - len;
291          if (write (u_trn_f, signature, len) != len) goto werror;
292     }
293
294     /* copy transaction from source_file, counting NL's. */
295     tfs = th.num_chars;
296     while (tfs > 0) {
297          tocopy = min (512, tfs);
298          tocopy = tread (source_file, buffer, tocopy, result);
299          if (*result) { core_abort (); return; }
300          for (bptr = buffer, i = 0; i < tocopy; bptr++,i++)
301               if (*bptr == '\n')
302                    th.num_lines++;
303          if (write (u_trn_f, buffer, tocopy) != tocopy) goto werror;
304          tfs -= tocopy;
305     }
306
307     tclose(source_file,result);
308     abort_file = NULL;
309
310     if (mtg_swapped)
311          swap_trn(&th);
312
313     lseek(u_trn_f, (long)(cb.trn_addr), SEEK_SET);
314     if (write (u_trn_f, (char *) &th, sizeof (trn_hdr)) != sizeof (trn_hdr)) goto werror;      /* update num_lines */
315
316     super.trn_fsize = fsize (u_trn_f);
317
318#if HAVE_ZEPHYR
319
320     /* Send this out...we want to do this BEFORE calling write_super
321      * because things get freed...
322      */
323     if (!(super.flags & MTG_NOZEPHYR))
324          mtg_znotify(mtg_name, subject, author, signature);
325#endif
326     
327     /* all done, start winding down */
328     write_super();
329
330     if (!no_nuke) {
331          fsync(u_trn_f);
332          aclose(a_control_f);
333          nuclear = 0;
334     }
335
336     *result = 0;
337     *result_trn = cb.current;
338     return;
339
340werror:
341     core_abort();
342     *result = NO_WRITE;
343     return;
344}
345/*
346 *
347 * expunge_trn () -- Entry to mark a given transaction as expunged.
348 *                   This makes a kosher chain_blk, except there's
349 *                   no transaction info associated with this.
350 *
351 */
352expunge_trn(mtg_name, desired_trn, result)
353char *mtg_name;
354trn_nums desired_trn;
355int *result;
356{
357     chain_blk cb;
358
359     *result = open_mtg (mtg_name);
360     if (*result) { core_abort (); return; }
361
362     if (!has_mtg_access('c')) {
363          *result = NO_ACCESS;
364          core_abort (); return;
365     }
366
367     if (!no_nuke) {
368          a_control_f = aopen (u_control_f);
369          nuclear = TRUE;
370     }
371
372     *result = read_super ();
373     if (*result) { core_abort(); return; }
374
375     if (desired_trn == 0 || desired_trn <= super.highest)
376          super.highest++;
377     else
378          super.highest = desired_trn;
379     
380     /* Initialize chain block */
381     cb.version = CHAIN_BLK_1;
382     cb.unique = CHAIN_BLK_UNIQUE;
383     cb.current = super.highest;
384     cb.prev = 0;
385     cb.next = 0;
386     cb.nref = 0;
387     cb.chain_fref = 0;
388     cb.chain_lref = 0;
389     cb.flags |= CB_DELETED;
390     cb.filler = 0;
391     cb.trn_addr = 0;
392
393     if (write_chain (&cb) != 0)                        /* write it out */
394          goto werror;
395
396     super.date_modified = time(0);
397     super.high_water += sizeof (chain_blk);
398
399     write_super();
400
401     if (!no_nuke) {
402          aclose(a_control_f);
403          nuclear = 0;
404     }
405
406     *result = 0;
407     return;
408
409werror:
410     core_abort();
411     *result = NO_WRITE;
412     return;
413}
414
415/*
416 *
417 * get_trn_info () --
418 * returns information about the given transaction in info, with an error
419 * code as its return argument
420 *
421 */
422get_trn_info (mtg_name, trn, info, result)
423char *mtg_name;
424trn_nums trn;
425trn_info *info;
426int *result;
427{
428     chain_blk cb,spare_cb;
429     trn_hdr th;
430     char *th_subject,*th_author;
431
432/*   printf ("get_trn_info: mtg %s, trn %d\n",
433             mtg_name, trn);*/
434
435     /* safety -- set info up right */
436     info -> version = 0;
437     info -> current = 0;
438     info -> prev = 0;
439     info -> next = 0;
440     info -> pref = 0;
441     info -> nref = 0;
442     info -> fref = 0;
443     info -> lref = 0;
444     info -> chain_index = 0;
445     info -> date_entered = 0;
446     info -> num_lines = 0;
447     info -> num_chars = 0;
448     info -> subject = new_string ("");
449     info -> author = new_string ("");
450
451
452     *result = open_mtg (mtg_name);
453     if (*result) return;
454
455     start_read();                              /* starting to read */
456
457     *result = read_super ();
458     if (*result) { core_abort(); return; }
459
460     *result = read_chain (trn, &cb);
461     if (*result) { core_abort(); return; }
462
463     if (cb.trn_addr == 0) {
464          *result = DELETED_TRN;
465          core_abort();
466          return;
467     }
468
469     *result = read_chain (cb.trn_chain, &spare_cb);
470     if (*result) { core_abort(); return; }
471
472     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, NULL);
473     if (*result) { core_abort(); return; }
474
475     finish_read();
476
477     if (!has_trn_access(th_author, 'r')) {
478          *result = NO_ACCESS;
479          goto null_info;
480     }
481
482     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
483          *result = DELETED_TRN;
484          goto null_info;
485     }
486
487     info -> version = 1;
488     info -> current = cb.current;
489     info -> prev = cb.prev;
490     info -> next = cb.next;
491     info -> pref = cb.pref;
492     info -> nref = cb.nref;
493     info -> fref = spare_cb.chain_fref;
494     info -> lref = spare_cb.chain_lref;
495     info -> chain_index = cb.trn_chain;
496
497     info -> date_entered = th.date_entered;
498     info -> num_lines = th.num_lines;
499     info -> num_chars = th.num_chars;
500     free (info -> subject);
501     info -> subject = th_subject;
502     free (info -> author);
503     info -> author = th_author;
504
505     forget_super();
506
507     if (cb.flags & CB_DELETED)
508          *result = DELETED_TRN;
509     else
510          *result = 0;
511null_info:
512     return;
513}
514
515/*
516 *
517 * get_trn_info2 () --
518 * returns information about the given transaction in info, with an error
519 * code as its return argument.  This call returns expanded information,
520 * such as the flags.
521 *
522 */
523get_trn_info2 (mtg_name, trn, info, result)
524char *mtg_name;
525trn_nums trn;
526trn_info2 *info;
527int *result;
528{
529     chain_blk cb,spare_cb;
530     trn_hdr th;
531     char *th_subject,*th_author;
532
533/*   printf ("get_trn_info: mtg %s, trn %d\n",
534             mtg_name, trn);*/
535
536     /* safety -- set info up right */
537     info -> version = 0;
538     info -> current = 0;
539     info -> prev = 0;
540     info -> next = 0;
541     info -> pref = 0;
542     info -> nref = 0;
543     info -> fref = 0;
544     info -> lref = 0;
545     info -> chain_index = 0;
546     info -> date_entered = 0;
547     info -> num_lines = 0;
548     info -> num_chars = 0;
549     info -> subject = new_string ("");
550     info -> author = new_string ("");
551     info -> flags = 0;
552
553     *result = open_mtg (mtg_name);
554     if (*result) return;
555
556     start_read();                              /* starting to read */
557
558     *result = read_super ();
559     if (*result) { core_abort(); return; }
560
561     *result = read_chain (trn, &cb);
562     if (*result) { core_abort(); return; }
563
564     if (cb.trn_addr == 0) {
565          *result = DELETED_TRN;
566          core_abort();
567          return;
568     }
569
570     *result = read_chain (cb.trn_chain, &spare_cb);
571     if (*result) { core_abort(); return; }
572
573     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, NULL);
574     if (*result) { core_abort(); return; }
575
576     finish_read();
577
578     if (!has_trn_access(th_author, 'r')) {
579          *result = NO_ACCESS;
580          goto null_info;
581     }
582
583     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
584          *result = DELETED_TRN;
585          goto null_info;
586     }
587
588     info -> version = 1;
589     info -> current = cb.current;
590     info -> prev = cb.prev;
591     info -> next = cb.next;
592     info -> pref = cb.pref;
593     info -> nref = cb.nref;
594     info -> fref = spare_cb.chain_fref;
595     info -> lref = spare_cb.chain_lref;
596     info -> chain_index = cb.trn_chain;
597
598     info -> date_entered = th.date_entered;
599     info -> num_lines = th.num_lines;
600     info -> num_chars = th.num_chars;
601     free (info -> subject);
602     info -> subject = th_subject;
603     free (info -> author);
604     info -> author = th_author;
605     info -> flags = cb.flags;
606
607     forget_super();
608
609     if (cb.flags & CB_DELETED)
610          *result = DELETED_TRN;
611     else
612          *result = 0;
613null_info:
614     return;
615}
616
617/*
618 *
619 * get_trn_info3 () --
620 * returns information about the given transaction in info, with an error
621 * code as its return argument.  This call returns expanded information,
622 * such as the flags and signature.
623 *
624 */
625get_trn_info3 (mtg_name, trn, info, result)
626char *mtg_name;
627trn_nums trn;
628trn_info3 *info;
629int *result;
630{
631     chain_blk cb,spare_cb;
632     trn_hdr th;
633     char *th_subject,*th_author, *th_signature;
634
635/*   printf ("get_trn_info: mtg %s, trn %d\n",
636             mtg_name, trn);*/
637
638     /* safety -- set info up right */
639     info -> version = 0;
640     info -> current = 0;
641     info -> prev = 0;
642     info -> next = 0;
643     info -> pref = 0;
644     info -> nref = 0;
645     info -> fref = 0;
646     info -> lref = 0;
647     info -> chain_index = 0;
648     info -> date_entered = 0;
649     info -> num_lines = 0;
650     info -> num_chars = 0;
651     info -> subject = new_string ("");
652     info -> author = new_string ("");
653     info -> signature = new_string ("");
654     info -> flags = 0;
655
656     *result = open_mtg (mtg_name);
657     if (*result) return;
658
659     start_read();                              /* starting to read */
660
661     *result = read_super ();
662     if (*result) { core_abort(); return; }
663
664     *result = read_chain (trn, &cb);
665     if (*result) { core_abort(); return; }
666
667     if (cb.trn_addr == 0) {
668          *result = DELETED_TRN;
669          core_abort();
670          return;
671     }
672
673     *result = read_chain (cb.trn_chain, &spare_cb);
674     if (*result) { core_abort(); return; }
675
676     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, &th_signature);
677     if (*result) { core_abort(); return; }
678
679     finish_read();
680
681     if (!has_trn_access(th_author, 'r')) {
682          *result = NO_ACCESS;
683          goto null_info;
684     }
685
686     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
687          *result = DELETED_TRN;
688          goto null_info;
689     }
690
691     info -> version = 1;
692     info -> current = cb.current;
693     info -> prev = cb.prev;
694     info -> next = cb.next;
695     info -> pref = cb.pref;
696     info -> nref = cb.nref;
697     info -> fref = spare_cb.chain_fref;
698     info -> lref = spare_cb.chain_lref;
699     info -> chain_index = cb.trn_chain;
700
701     info -> date_entered = th.date_entered;
702     info -> num_lines = th.num_lines;
703     info -> num_chars = th.num_chars;
704     free (info -> subject);
705     info -> subject = th_subject;
706     free (info -> author);
707     info -> author = th_author;
708     free (info -> signature);
709     info -> signature = th_signature;
710     info -> flags = cb.flags;
711
712     forget_super();
713
714     if (cb.flags & CB_DELETED)
715          *result = DELETED_TRN;
716     else
717          *result = 0;
718null_info:
719     return;
720}
721
722
723/*
724 *
725 * set_trn_flags () -- Routine to set the flags (except DELETED) on a
726 *                     given transaction.
727 *
728 */
729set_trn_flags (mtg_name, trn, flags, result)
730char *mtg_name;
731trn_nums trn;
732short flags;
733int *result;
734{
735     chain_blk cb;
736     trn_hdr th;
737     char *th_author;
738
739     *result = open_mtg (mtg_name);
740     if (*result) return;
741
742     if (!no_nuke) {
743          a_control_f = aopen (u_control_f);
744          nuclear = TRUE;
745     }
746
747     *result = read_super ();
748     if (*result) { core_abort(); return; }
749
750     *result = read_chain (trn, &cb);
751     if (*result) { core_abort(); return; }
752
753     if ((cb.flags & CB_DELETED) || cb.trn_addr == 0) {
754          *result = DELETED_TRN;
755          core_abort (); return;
756     }
757
758     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
759     if (*result) { core_abort(); return; }
760
761     if (!has_trn_access(th_author,'d')) {
762          *result = NO_ACCESS;
763          free(th_author);
764          core_abort(); return;
765     }
766
767     free(th_author);
768
769     cb.flags = (cb.flags & CB_DELETED) | (flags & ~CB_DELETED);
770     write_chain (&cb);
771
772     forget_super();
773
774     if (!no_nuke) {
775          aclose (a_control_f);
776          nuclear = FALSE;
777     }
778
779     *result = 0;
780     return;
781}
782
783
784
785/*
786 *
787 * delete_trn () --
788 * deletes the given transaction from the current meeting.  Returns an
789 * error code
790 *
791 */
792delete_trn (mtg_name, trn, result)
793char *mtg_name;
794trn_nums trn;
795int *result;
796{
797     chain_blk cb, spare_cb;
798     char *th_author;
799     trn_hdr th;
800
801/*   printf ("delete_trn: mtg %s, trn %d\n",
802             mtg_name, trn);*/
803
804     *result = open_mtg (mtg_name);
805     if (*result) return;
806
807     if (!no_nuke) {
808          a_control_f = aopen (u_control_f);
809          nuclear = TRUE;
810     }
811
812     *result = read_super ();
813     if (*result) { core_abort(); return; }
814
815     *result = read_chain (trn, &cb);
816     if (*result) { core_abort(); return; }
817
818     if ((cb.flags & CB_DELETED) || cb.trn_addr == 0) {
819          *result = DELETED_TRN;
820          core_abort (); return;
821     }
822
823     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
824     if (*result) { core_abort(); return; }
825
826     if (!has_trn_access(th_author,'d')) {
827          *result = NO_ACCESS;
828          free(th_author);
829          core_abort(); return;
830     }
831
832     free(th_author);
833     
834     cb.flags |= CB_DELETED;
835     write_chain (&cb);
836
837     /* update next of prev */
838     if (cb.prev != 0) {
839          *result = read_chain (cb.prev, &spare_cb);
840          if (*result) { core_abort(); return; }
841
842          spare_cb.next = cb.next;
843          write_chain (&spare_cb);
844     }
845
846     /* update prev of next */
847     if (cb.next != 0) {
848          *result = read_chain (cb.next, &spare_cb);
849          if (*result) { core_abort(); return; }
850
851          spare_cb.prev = cb.prev;
852          write_chain (&spare_cb);
853     }
854
855     /* update nref of pref */
856     if (cb.pref != 0) {
857          *result = read_chain (cb.pref, &spare_cb);
858          if (*result) { core_abort(); return; }
859
860          spare_cb.nref = cb.nref;
861          write_chain (&spare_cb);
862     }
863
864     /* update pref of nref */
865     if (cb.nref != 0) {
866          *result = read_chain (cb.nref, &spare_cb);
867          if (*result) { core_abort(); return; }
868
869          spare_cb.pref = cb.pref;
870          write_chain (&spare_cb);
871     }
872
873     /* and update fref & lref of chain */
874     if (cb.nref == 0 || cb.pref == 0) {
875          *result = read_chain (cb.trn_chain, &spare_cb);
876          if (*result) { core_abort(); return; }
877
878          if (cb.nref == 0)
879               spare_cb.chain_lref = cb.pref;
880          if (cb.pref == 0)
881               spare_cb.chain_fref = cb.nref;
882          write_chain (&spare_cb);
883     }
884
885     /* and update, first and last of meeting */
886     if (cb.prev == 0)
887          super.first = cb.next;
888     if (cb.next == 0)
889          super.last = cb.prev;
890
891     write_super ();
892     if (!no_nuke) {
893          aclose (a_control_f);
894          nuclear = FALSE;
895     }
896
897     *result = 0;
898     return;
899}
900
901/*
902 *
903 * retrieve_trn () --
904 * retrieves a previously deleted transaction from the current meeting, if
905 * possible.  trn must refer to a deleted transaction.  An error code is
906 * returned
907 *
908 */
909retrieve_trn (mtg_name, trn, result)
910char *mtg_name;
911trn_nums trn;
912int *result;
913{
914     chain_blk cb, spare_cb, chain_cb;
915     trn_hdr th;
916     char *th_author;
917
918
919/*   printf ("retrieve_trn: mtg %s, trn %d\n",
920             mtg_name, trn);*/
921
922
923     *result = open_mtg (mtg_name);
924     if (*result) return;
925
926     if (!no_nuke) {
927          a_control_f = aopen (u_control_f);
928          nuclear = TRUE;
929     }
930
931     *result = read_super ();
932     if (*result) { core_abort(); return; }
933
934     *result = read_chain (trn, &cb);
935     if (*result) { core_abort(); return; }
936
937     if (!(cb.flags & CB_DELETED)) {
938          *result = TRN_NOT_DELETED;
939          core_abort (); return;
940     }
941
942     if (cb.trn_addr == 0) {
943          *result = EXPUNGED_TRN;
944          core_abort (); return;
945     }
946
947     /* for paranoia, read transaction */
948     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
949     if (*result) { core_abort(); return; }
950
951     if (!has_trn_access(th_author,'d')) {
952          *result = NO_ACCESS;
953          free(th_author);
954          core_abort(); return;
955     }
956
957     free(th_author);
958
959     /* now retrieving a transaction is hairier than deleting it, since
960        the previous and next, pref and nref could also have been deleted
961        since.  Also, intermediate ones could have been retrieved in the
962        interim.  So we go to our reference points (fref & lref), and
963        start from there.  There are three cases -- we are the new fref,
964        we are the new lref, or we are in the middle.  For prev & next,
965        we just start decrementing and incrementing until we get a
966        non-deleted transaction */
967     
968     *result = read_chain (cb.trn_chain, &chain_cb);
969     if (*result) { core_abort(); return; }
970
971     if (chain_cb.chain_fref > cb.current || chain_cb.chain_fref == 0) /* we are fref */
972          cb.pref = 0;
973     else
974          cb.pref = chain_cb.chain_fref;
975
976     if (chain_cb.chain_lref < cb.current)
977          cb.nref = 0;
978     else
979          cb.nref = chain_cb.chain_lref;
980
981     /* advance until we get past us */
982     while (cb.pref != 0) {
983          *result = read_chain (cb.pref, &spare_cb);
984          if (*result) { core_abort(); return; }
985
986          if (spare_cb.nref > cb.current || spare_cb.nref == 0)
987               break;
988          cb.pref = spare_cb.nref;
989     }
990
991     while (cb.nref != 0) {
992          *result = read_chain (cb.nref, &spare_cb);
993          if (*result) { core_abort(); return; }
994
995          if (spare_cb.pref < cb.current)
996               break;
997          cb.nref = spare_cb.pref;
998     }
999
1000     if (super.first > cb.current || super.first == 0) /* we are first */
1001          cb.prev = 0;
1002     else
1003          cb.prev = cb.current - 1;
1004
1005     if (super.last < cb.current)
1006          cb.next = 0;
1007     else
1008          cb.next = cb.current + 1;
1009
1010     while (cb.prev != 0) {
1011          *result = read_chain (cb.prev, &spare_cb);
1012          if (*result) { core_abort(); return; }
1013
1014          if (!(spare_cb.flags & CB_DELETED))
1015               break;
1016          cb.prev--;
1017     }
1018     while (cb.next != 0) {
1019          *result = read_chain (cb.next, &spare_cb);
1020          if (*result) { core_abort(); return; }
1021
1022          if (!(spare_cb.flags & CB_DELETED))
1023               break;
1024          cb.next++;
1025     }
1026
1027     /* invariant -- current_block is all set (except for deleted) */
1028     cb.flags &= ~(CB_DELETED);
1029     write_chain (&cb);
1030
1031     /* update next of prev */
1032     if (cb.prev != 0) {
1033          *result = read_chain (cb.prev, &spare_cb);
1034          if (*result) { core_abort(); return; }
1035
1036          spare_cb.next = cb.current;
1037          write_chain (&spare_cb);
1038     }
1039
1040     /* update prev of next */
1041     if (cb.next != 0) {
1042          *result = read_chain (cb.next, &spare_cb);
1043          if (*result) { core_abort(); return; }
1044
1045          spare_cb.prev = cb.current;
1046          write_chain (&spare_cb);
1047     }
1048
1049     /* update nref of pref */
1050     if (cb.pref != 0) {
1051          *result = read_chain (cb.pref, &spare_cb);
1052          if (*result) { core_abort(); return; }
1053
1054          spare_cb.nref = cb.current;
1055          write_chain (&spare_cb);
1056     }
1057
1058     /* update pref of nref */
1059     if (cb.nref != 0) {
1060          *result = read_chain (cb.nref, &spare_cb);
1061          if (*result) { core_abort(); return; }
1062
1063          spare_cb.pref = cb.current;
1064          write_chain (&spare_cb);
1065     }
1066
1067     /* and update fref & lref of chain */
1068     if (cb.nref == 0 || cb.pref == 0) {
1069          *result = read_chain (cb.trn_chain, &spare_cb);
1070          if (*result) { core_abort(); return; }
1071
1072          if (cb.nref == 0)
1073               spare_cb.chain_lref = cb.current;
1074          if (cb.pref == 0)
1075               spare_cb.chain_fref = cb.current;
1076          write_chain (&spare_cb);
1077     }
1078
1079     /* and update, first and last of meeting */
1080     if (cb.prev == 0)
1081          super.first = cb.current;
1082     if (cb.next == 0)
1083          super.last = cb.current;
1084
1085     write_super ();
1086     if (!no_nuke) {
1087          aclose (a_control_f);
1088          nuclear = FALSE;
1089     }
1090
1091     *result = 0;
1092     return;
1093}
1094
1095
1096
1097/*
1098 *
1099 * create_mtg () --
1100 * Creates a new meeting with the given long_mtg name, where location is the
1101 * it's place in the hierarchy, and the long_mtg_name is its canonical name.
1102 * The chairman of the new meeting is the current user.
1103 *
1104 */
1105create_mtg (location, long_mtg_name, public, result)
1106char *location,*long_mtg_name;
1107bool public;
1108int *result;
1109{
1110     create_mtg_priv (location, long_mtg_name, public, (date_times) time ((long *)0), rpc_caller, NULL, result);
1111}
1112
1113/* create_mtg_priv -- for people who know the chairman and date_created */
1114create_mtg_priv (location, long_mtg_name, public, date_created, chairman, new_acl, result)
1115char *location,*long_mtg_name,*chairman;
1116bool public;
1117date_times date_created;
1118dsc_acl *new_acl;
1119int *result;
1120{
1121     char str[256];
1122     trn_base tb;
1123     int loclen;
1124
1125/*   printf("create_mtg: long mtg %s, location %s, public %d\n",
1126            long_mtg_name, location, public);*/
1127
1128     loclen = strlen (location);
1129     if (location[0] != '/' || loclen == 0 || loclen >= MAXPATHLEN || location [loclen-1] == '/' || loclen+14 >= sizeof(str)) {
1130          *result = BAD_PATH;
1131          return;
1132     }
1133
1134     if (long_mtg_name [0] == '\0') {
1135          *result = BAD_MTG_NAME;
1136          return;
1137     }
1138
1139     /* First, create meeting directory */
1140     umask (077);                               /* Set access for sure */
1141     if (mkdir (location, 0700) < 0) {          /* rwx------ */
1142          if (errno == EEXIST)
1143               *result = DUP_MTG_NAME;
1144          else
1145               *result = BAD_PATH;
1146          return;
1147     }
1148
1149     /*
1150      * Then see if we should have access to build it..  Yes, this is
1151      * a crock, but UNIX doesn't have an easy way to
1152      * canonicalize a pathname
1153      */
1154
1155     *result = 0;
1156     
1157     if (!has_privs) {
1158          int aclfd;
1159          strcpy (str, location);
1160          strcat (str, "/../cacl");
1161
1162          if ((aclfd = open(str, O_RDONLY, 0700)) < 0) {
1163               *result = NO_ACCESS;
1164          } else {
1165               dsc_acl *tmp_acl = acl_read(aclfd);
1166               (void) close(aclfd);
1167
1168               if (tmp_acl == NULL ||
1169                   !acl_check(tmp_acl, rpc_caller, "a"))
1170                       *result = NO_ACCESS;
1171               (void) acl_destroy(tmp_acl);
1172          }
1173          if (*result) {
1174               (void) rmdir(location); /* we don't care if this fails; */
1175                                       /* we can't do anything about it */
1176               return;
1177          }
1178     }
1179     
1180     strcpy (str, location);
1181     strcat (str, "/control");
1182
1183     if ((u_control_f = open(str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1184          if (errno == EEXIST)
1185               *result = DUP_MTG_NAME;
1186          else if (errno == EACCES)
1187               *result = NO_ACCESS;
1188          else
1189               *result = BAD_PATH;
1190          return;
1191     }
1192     
1193     strcpy (str, location);
1194     strcat (str, "/transactions");
1195     
1196     if ((u_trn_f = open(str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1197          if (errno == EEXIST)
1198               *result = DUP_MTG_NAME;
1199          else if (errno == EACCES)
1200               *result = NO_ACCESS;
1201          else
1202               *result = BAD_PATH;
1203          close (u_control_f);
1204          return;
1205     }
1206
1207     mtg_swapped = FALSE;
1208
1209     /* Initialize super-block */
1210     super.version = MTG_SUPER_1;
1211     super.unique = MTG_SUPER_UNIQUE;
1212     super.first = 0;
1213     super.last = 0;
1214     super.lowest = 1;
1215     super.highest = 0;
1216     super.highest_chain = 0;
1217     super.date_created = super.date_modified = date_created;
1218     super.long_name_addr = 0;
1219     super.chairman_addr = 0;
1220     super.long_name_len = 0;
1221     super.chairman_len = 0;
1222
1223     super_long_name = new_string (long_mtg_name);
1224     super_chairman = new_string (chairman);
1225     super.flags = public ? MTG_PUBLIC : 0;
1226     super.chain_start = 1024;
1227     super.high_water = super.chain_start;
1228     super.trn_fsize = 0;
1229     super.highest_trn_addr = 0;
1230
1231     /* initialize trn_base */
1232     tb.version = TRN_BASE_1;
1233     tb.unique = TRN_BASE_UNIQUE;
1234     tb.date_created = super.date_created;
1235     tb.public_flag = public;
1236
1237     /* calculate address & lens of variable length fields */
1238     tb.long_name_addr = sizeof (tb);
1239     tb.long_name_len = strlen (super_long_name) + 1;
1240     tb.chairman_addr = tb.long_name_addr + tb.long_name_len;
1241     tb.chairman_len = strlen (super_chairman) + 1;
1242     write (u_trn_f, (char *) &tb, sizeof (tb));        /* trn base */
1243     write (u_trn_f, super_long_name, tb.long_name_len);
1244     write (u_trn_f, super_chairman, tb.chairman_len);
1245
1246     super.trn_fsize = sizeof (tb) + tb.long_name_len + tb.chairman_len;
1247
1248     write_super();
1249     
1250     strcpy (current_mtg, location);                    /* it's legal */
1251     if (mtg_acl != NULL)
1252          acl_destroy(mtg_acl);
1253     if (new_acl == NULL) {
1254          mtg_acl = acl_create ();
1255          acl_add_access(mtg_acl, chairman, "acdorsw"); /* add chairman */
1256          if (public == 1)
1257               acl_add_access(mtg_acl, "*", "a  orsw"); /* public mtg */
1258     } else
1259          mtg_acl = acl_copy(new_acl);
1260
1261
1262     strcpy (str, location);
1263     strcat (str, "/acl");
1264
1265     if ((u_acl_f = open (str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1266          *result = BAD_PATH;
1267          return;
1268     }
1269     acl_write (u_acl_f, mtg_acl);
1270     close (u_acl_f);
1271
1272     *result = 0;
1273     return;
1274}
1275
1276
1277/*
1278 *
1279 * get_mtg_info () --
1280 * returns information about the given meeting.  Return argument is an
1281 * error code
1282 *
1283 */
1284get_mtg_info (mtg_name, info, result)
1285char *mtg_name;
1286mtg_info *info;
1287int *result;
1288{
1289/*   printf ("get_mtg_info: mtg %s\n",
1290             mtg_name);*/
1291
1292     /* safety -- set strings up right */
1293     info -> chairman = new_string ("");
1294     info -> long_name = new_string ("");
1295     info -> location = new_string (mtg_name);
1296     info -> access_modes = new_string ("");
1297     info -> public_flag = TRUE;
1298
1299     *result = open_mtg (mtg_name);
1300     if (*result) {
1301          if (*result == MTG_MOVED) {
1302               char buf[100];
1303               int mf;
1304               char *cp;
1305
1306               snprintf(buf, sizeof(buf), "%s/forward", mtg_name);
1307               if ((mf = open(buf, O_RDONLY, 0700)) < 0) {
1308                    *result = INCONSISTENT;
1309                    return;
1310               }
1311               if (read(mf, buf, 100) < 0) {
1312                    *result = INCONSISTENT;
1313                    close(mf);
1314                    return;
1315               }
1316               close(mf);
1317               cp = strchr(buf, '\n');
1318               if (cp == NULL) {
1319                    *result = INCONSISTENT;
1320                    return;
1321               }
1322               *cp = '\0';
1323               cp = strchr(buf, ':');
1324               if (cp == NULL) {
1325                    *result = INCONSISTENT;
1326                    return;
1327               }
1328               *cp++ = '\0';
1329               free(info -> long_name);
1330               info -> long_name = new_string (buf);
1331               free(info -> location);
1332               info -> location = new_string (cp);
1333          }
1334          return;
1335     }
1336
1337     free(info -> access_modes);
1338     info -> access_modes = new_string (acl_get_access(mtg_acl, rpc_caller));
1339
1340     if (!has_mtg_access('s') && !has_mtg_access('r')) {
1341          *result = NO_ACCESS;
1342          return;
1343     }
1344
1345     start_read();                              /* starting to read */
1346
1347     *result = read_super ();
1348     if (*result) { core_abort(); return; }
1349
1350     finish_read();
1351
1352     info -> version = 2;
1353     free(info -> long_name);
1354     free(info -> chairman);
1355
1356     info -> long_name = new_string (super_long_name);
1357     info -> chairman = new_string (super_chairman);
1358     info -> first = super.first;
1359     info -> last = super.last;
1360     info -> lowest = super.lowest;
1361     info -> highest = super.highest;
1362     info -> date_created = super.date_created;
1363     info -> date_modified = super.date_modified;
1364     info -> public_flag = (super.flags & MTG_PUBLIC);
1365
1366     forget_super();
1367
1368     *result = 0;
1369     return;
1370}
1371
1372/*
1373 *
1374 * get_trn () --
1375 * gets the given transaction, and feeds it through dest_file.  Returns an
1376 * error code
1377 *
1378 */
1379get_trn (mtg_name, trn, dest_file, result)
1380char *mtg_name;
1381trn_nums trn;
1382tfile dest_file;
1383int *result;
1384{
1385     chain_blk cb;
1386     trn_hdr th;
1387     char buffer [512];
1388     int tocopy, tfs;
1389     char *th_author;
1390
1391/*   printf ("get_trn: mtg %s, trn %d\n",
1392             mtg_name, trn);*/
1393
1394     topen (dest_file, "w", result);
1395     abort_file = dest_file;
1396
1397     *result = open_mtg (mtg_name);
1398     if (*result) { core_abort (); return; }
1399
1400     start_read();                              /* starting to read */
1401
1402     *result = read_super ();
1403     if (*result) { core_abort(); return; }
1404
1405     *result = read_chain (trn, &cb);
1406     if (*result) { core_abort(); return; }
1407
1408     if (cb.trn_addr == 0) {
1409          *result = DELETED_TRN;
1410          core_abort();
1411          return;
1412     }
1413
1414     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
1415     if (*result) { core_abort(); return; }
1416
1417     finish_read();
1418
1419     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
1420
1421          *result = DELETED_TRN;
1422          free(th_author);
1423          core_abort(); return;
1424     }
1425     if (!has_trn_access(th_author,'r')) {
1426          *result = NO_ACCESS;
1427          free(th_author);
1428          core_abort(); return;
1429     }
1430
1431     (void) free(th_author);
1432
1433     lseek (u_trn_f, (long)(th.text_addr), SEEK_SET);
1434     tfs = th.num_chars;
1435     while (tfs > 0) {
1436          tocopy = min (512, tfs);
1437          read (u_trn_f, buffer, tocopy);
1438          twrite (dest_file, buffer, tocopy,result);
1439          tfs -= tocopy;
1440     }
1441
1442     tclose (dest_file,result);
1443     abort_file = NULL;
1444
1445     if (cb.flags & CB_DELETED)
1446          *result = DELETED_TRN;
1447     else
1448          *result = 0;
1449     return;
1450}
1451
1452/*
1453 *
1454 * remove_mtg () --
1455 * removes the given meeting  -- the physical contents of the meeting
1456 * are destroyed.
1457 *
1458 */
1459remove_mtg (mtg_name, result)
1460char *mtg_name;
1461int *result;
1462{
1463     char str[256];
1464
1465
1466/*   printf ("remove_mtg: mtg %s\n",
1467             mtg_name);*/
1468     
1469     *result = open_mtg (mtg_name);
1470     if (*result) return;
1471
1472     if (!has_mtg_access('c')) {
1473          *result = NO_ACCESS;
1474          return;
1475     }
1476         
1477     strcpy (str, mtg_name);
1478     strcat (str, "/control");
1479
1480     if (unlink (str) < 0) {
1481          if (errno != ENOENT) {
1482               *result = CANNOT_REMOVE;
1483               return;
1484          }
1485     }
1486
1487     strcpy (str, mtg_name);
1488     strcat (str, "/transactions");
1489
1490     unlink (str);
1491
1492     strcpy (str, mtg_name);
1493     strcat (str, "/acl");
1494
1495     unlink (str);
1496
1497     *result = 0;
1498     if (rmdir (mtg_name) < 0)
1499          *result = CANNOT_REMOVE;
1500
1501     *result = read_super();
1502     super.date_created = 0;
1503     write_super();
1504
1505     close (u_trn_f);                           /* bombs away */
1506     close (u_control_f);
1507     if (u_acl_f)
1508          close (u_acl_f);
1509     acl_destroy(mtg_acl);
1510     mtg_acl = NULL;
1511     current_mtg [0] = '\0';
1512
1513     return;
1514}
1515
1516/*
1517 *
1518 * updated_mtg () -- Quick procedure to check if the meeting is updated
1519 *                   with respect to a given time and transaction number.
1520 *                   An efficient procedure for a common operation -- doesn't
1521 *                   open the meeting unless it has to.
1522 *
1523 */
1524updated_mtg (mtg_name, date_attended, last, updated, result)
1525char *mtg_name;
1526int date_attended, last;
1527bool *updated;
1528int *result;
1529{
1530     char str[256];
1531     int mtg_name_len;
1532     mtg_super mysuper;
1533     struct stat sb;
1534     int uf;
1535
1536     *updated = 0;
1537     *result = 0;                               /* optimist */
1538
1539     mtg_name_len = strlen (mtg_name);
1540     if (mtg_name[0] != '/' || mtg_name_len == 0 || mtg_name_len >= MAXPATHLEN || mtg_name [mtg_name_len-1] == '/' || mtg_name_len + 9 >= sizeof(str)) {
1541          *result = BAD_PATH;
1542          return;
1543     }
1544
1545     strcpy (str, mtg_name);
1546     strcat (str, "/forward");
1547     if (!stat(str, &sb)) {             /* Show moved meetings as changed */
1548          *updated = TRUE;
1549          *result = 0;
1550          return;
1551     }
1552
1553     strcpy (str, mtg_name);
1554     strcat (str, "/control");
1555
1556     /* time makes no difference in our books */
1557     if ((uf = open(str, O_RDWR, 0700)) < 0) {
1558          if (errno == ENOENT)
1559               *result = NO_SUCH_MTG;
1560          else if (errno == EACCES)
1561               *result = NO_ACCESS;
1562          else
1563               *result = BAD_PATH;
1564          goto punt;
1565     }
1566
1567     /* forget locking (and stuff) for what we're doing */
1568     lseek (uf, (long)0, SEEK_SET);
1569     read (uf, (char *) &mysuper, sizeof (mysuper));
1570     close(uf);
1571
1572     if (mysuper.unique == MTG_SUPER_UNIQUE_SWAP)
1573          swap_super(&mysuper);
1574
1575     *updated = (mysuper.last > last);
1576     if (mysuper.highest < last)
1577          *result = NO_SUCH_TRN;
1578
1579punt:
1580     return;
1581}
Note: See TracBrowser for help on using the repository browser.