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

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