system/multiuser/1.7.5/src/archive manager

Raw file
Back to index

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
(* ------------------- VERSION 10 vom 17.04.86 ------------------- *)
PACKET archive manager DEFINES                 (* Autor: J.Liedtke*)
 
      archive manager ,
      provide channel :



LET std archive channel  = 31 ,

    ack              = 0 ,
    nak              = 1 ,
    error nak        = 2 ,
    second phase ack = 5 ,
    false code       = 6 ,
 
    fetch code       = 11 ,
    save code        = 12 ,
    exists code      = 13 ,
    erase code       = 14 ,
    list code        = 15 ,
    all code         = 17 ,
    clear code       = 18 ,
    reserve code     = 19 ,
    free code        = 20 ,
    check read code  = 22 ,
    format code      = 23 ,

    read error       = 92 ,
 
    max files = 200 ,
 
    start of volume = 1000 ,
    end of volume = 1 ,
    file header   = 3 , 

    number of header blocks = 2 ,
 
    quote         = """" ,
    dummy name    = "-" ,
    dummy date    = "        " ,

 
    HEADER = STRUCT (TEXT name, date, INT type, TEXT password) ;


BOUND STRUCT (TEXT name, pass) VAR msg ;

INT VAR archive channel := std archive channel ;

TASK VAR archive owner := niltask ,
         order task ;
TEXT VAR archive name := "" , write stamp ;

REAL VAR last access time := 0.0 ;

BOOL VAR was already write access ;


DATASPACE VAR header space := nilspace ;
BOUND HEADER VAR header ;

TEXT VAR file name := "" ;

LET invalid   = 0 ,
    read only = 1 ,
    valid     = 2 ;

LET accept read errors = TRUE ,
    ignore read errors = FALSE ;


INT VAR directory state := invalid ;

THESAURUS VAR directory ;
INT VAR dir index ;

INT VAR archive size ;

INT VAR end of volume block ;
ROW max files INT VAR header block ;
ROW max files TEXT VAR header date ;


 
PROC provide channel (INT CONST channel) :

  archive channel := channel

ENDPROC provide channel ;

PROC archive manager :

  archive manager (archive channel)

ENDPROC archive manager ;

PROC archive manager (INT CONST channel) :

  archive channel := channel ;
  task password ("-") ;
  global manager 
     (PROC (DATASPACE VAR, INT CONST, INT CONST, TASK CONST) archive manager)

ENDPROC archive manager ;

PROC archive manager (DATASPACE VAR ds, INT CONST order, phase,
                      TASK CONST task) :


  enable stop ;
  order task := task ;
  msg := ds ;
  SELECT order OF
    CASE fetch code       : fetch file
    CASE save code        : save file
    CASE exists code      : exists file
    CASE erase code       : erase file
    CASE list code        : list (ds); manager ok (ds)
    CASE all code         : deliver directory
    CASE clear code,
         format code      : clear or format
    CASE reserve code     : reserve 
    CASE free code        : free
    CASE check read code  : check
    OTHERWISE errorstop (name (myself) + ": unbekannter Auftrag")
  ENDSELECT .

deliver directory :
  access archive ;
  BOUND THESAURUS VAR all names := ds ;
  all names := directory ;
  WHILE all names CONTAINS dummy name REP
    delete (all names, dummy name, dir index)
  PER ;
  manager ok (ds) .

clear or format :
  IF NOT (order task = archive owner)
    THEN errorstop ("Archiv nicht angemeldet")
  ELIF phase = 1
    THEN ask for erase all
  ELSE   directory state := invalid ;
         IF order <> clear code
           THEN format archive (specification) ;
                archive size := archive blocks
         FI ;
         rewind ;
         write header (archive name, text (clock(1),13,1), start of volume);
         write end of volume ;
         manager ok (ds)
  FI .

ask for erase all :
  IF order = format code AND specification > 3
    THEN errorstop ("ungueltiger Format-Code")
  FI ;
  look at volume header ;
  IF header.name <> ""
    THEN IF order = clear code
           THEN manager question ("Archiv """+header.name+""" loeschen", order task) 
           ELSE manager question ("Archiv """+header.name+""" formatieren", order task) 
         FI 
    ELSE IF order = clear code
           THEN manager question ("Archiv initialisieren", order task) 
           ELSE manager question ("Archiv formatieren", order task)
         FI
  FI .

specification :
  int (msg.name) .

reserve :
  IF reserve or free permitted
     THEN continue archive channel;
          disable stop ;
          directory state := invalid ;
          archive owner := order task ;
          archive name := msg.name ;
          manager ok (ds)
     ELSE errorstop ("Archiv wird von Task """+name(archive owner)+""" benutzt")
  FI .

continue archive channel :
  continue channel (archive channel) .

free :
  IF reserve or free permitted 
    THEN archive owner := niltask ;
         break (quiet) ;
         manager ok (ds)
    ELSE manager message ("Archiv nicht angemeldet", order task)
  FI.

reserve or free permitted :
     order task = archive owner OR last access more than five minutes ago
     OR archive owner = niltask OR NOT
     (exists (archive owner) OR station (archive owner) <> station (myself)) .
 
last access more than five minutes ago :
     abs (last access time - clock (1)) > 300.0 .

fetch file :
  access archive ;
  access file (msg.name) ;
  IF no read error remarked
    THEN disable stop ;
         fetch (ds, accept read errors) ;
         IF read error occurred
           THEN remark read error
         FI ;
         enable stop
    ELSE fetch (ds, ignore read errors)
  FI ;
  manager ok (ds) .

no read error remarked :
  pos (file name, " mit Lesefehler") = 0 .

read error occurred :
  is error AND error code = read error .

remark read error :
  dir index := link (directory, file name) ;
  REP
    file name CAT " mit Lesefehler" ;
  UNTIL NOT (directory CONTAINS file name) PER ;
  IF LENGTH file name < 100
    THEN rename (directory, dir index, file name)
  FI .

save file :
  IF phase = 1
    THEN access archive ;
         access file (msg.name) ;
         IF file in directory
           THEN manager question (""""+file name +""" ueberschreiben", order task)
           ELSE send (order task, second phase ack, ds)
         FI
    ELSE access archive ;
         access file (file name) ;
         erase ;
         save (ds) ;
         forget (ds) ;
         ds := nilspace ;
         manager ok (ds)
  FI .

exists file :
  access archive ;
  access file (msg.name) ;
  IF file in directory
    THEN manager ok (ds)
    ELSE send (order task, false code, ds)
  FI .

erase file :
  access archive ;
  access file (msg.name) ;
  IF file in directory
    THEN IF phase = 1
           THEN manager question (""""+file name+""" loeschen", order task)
           ELSE erase ; manager ok (ds)
         FI
    ELSE manager message ("gibt es nicht", order task)
  FI .

check :
  access archive ;
  access file (msg.name) ;
  IF file in directory
    THEN position to file ;
         disable stop ;
         check read ;
         IF is error
           THEN clear error; error ("fehlerhaft")
           ELSE last access time := clock (1) ;
                manager message ("""" + file name + """ ohne Fehler gelesen", order task)
         FI
    ELSE error ("gibt es nicht")
  FI .

file in directory :  dir index > 0 .

position to file :
  seek (header block (dir index) + number of header blocks) .

ENDPROC archive manager ;

PROC manager ok (DATASPACE VAR ds) :

  send (order task, ack, ds) ;
  last access time := clock (1) .

ENDPROC manager ok ;

PROC access archive :
 
  IF NOT (order task = archive owner)
    THEN errorstop ("Archiv nicht angemeldet")
  ELIF directory state = invalid
    THEN open archive
  ELIF last access more than two seconds ago
    THEN check volume name ;
         new open if somebody changed medium
  FI .

last access more than two seconds ago :
  abs (clock (1) - last access time) > 2.0 .

new open if somebody changed medium :
  IF header.date <> write stamp
    THEN directory state := invalid ;
         access archive
  FI .

open archive :
  directory state := invalid ;
  check volume name ;
  write stamp := header.date ;
  was already write access := FALSE ;
  read directory ;
  make directory valid if no read errors occurred .

read directory :
  directory := empty thesaurus ;
  rewind ;
  get next header ;
  WHILE header.type = file header REP
    IF directory CONTAINS header.name
      THEN rename (directory, header.name, dummy name)
    FI ;
    insert (directory, header.name, dir index) ;
    header block (dir index) := end of volume block ;
    header date (dir index)  := header.date ;
    get next header ;
  PER .

make directory valid if no read errors occurred :
  IF directory state = invalid
    THEN directory state := valid
  FI .

ENDPROC access archive ;

PROC access file (TEXT CONST name) :

  file name := name ;
  dir index := link (directory, file name) .

ENDPROC access file ;


PROC check volume name :

  disable stop ;
  archive size := archive blocks ;
  read volume header ;
  IF header.type <> start of volume
    THEN simulate header (start of volume, "?????")
  ELIF header.name <> archive name
    THEN errorstop ("Archiv heisst """ + header.name + """")
  FI .

read volume header :
  rewind ;
  read header ;
  IF is error AND error code = read error
    THEN clear error ;
         simulate header (start of volume, "?????")
  FI .

ENDPROC check volume name ;

PROC get next header :

  disable stop ;
  skip dataspace ;
  IF NOT is error
    THEN read header
  FI ;
  IF is error
    THEN clear error ;
         directory state := read only ;
         search header
  FI ;
  end of volume block := block number - number of header blocks .

search header :
  INT VAR ds pages ;
  search dataspace (ds pages) ;
  IF ds pages < 0
    THEN simulate header (end of volume, "")
  ELIF NOT is header space
    THEN simulate header (file header, "????? " + text (block number))
  FI .

is header space :
  IF ds pages <> 1
    THEN FALSE
    ELSE remember position ;
         read header ;
         IF read error occurred
           THEN clear error; back to old position; FALSE
         ELIF header format looks ok
           THEN TRUE
           ELSE back to old position ; FALSE
         FI
  FI .

read error occurred :
  is error CAND error code = read error .

header format looks ok :
  header.type = file header OR header.type = end of volume .

remember position :
  INT CONST old block nr := block number .

back to old position :
  seek (old block nr) .

ENDPROC get next header ;

PROC fetch (DATASPACE VAR ds, BOOL CONST error accept):

  enable stop ;
  IF file name <> dummy name
    THEN fetch from archive
    ELSE error ("Name unzulaessig")
  FI .

fetch from archive :
  IF file in directory
    THEN position to file ;
         read (ds, 30000, error accept)
  ELIF directory state = read only
    THEN error ("gibt es nicht (oder Lesefehler)")
    ELSE error ("gibt es nicht")
  FI .

position to file :
  seek (header block (dir index) + number of header blocks) .

file in directory :  dir index > 0 .
 
ENDPROC fetch ;

PROC erase :

  IF directory state = read only
    THEN errorstop ("'save'/'erase' wegen Lesefehler verboten")
    ELSE update write stamp if first write access ;
         erase archive
  FI .

update write stamp if first write access :
  IF NOT was already write access 
    THEN rewind ;
         write stamp := text (clock (1), 13, 1) ;
         write header (archive name, write stamp, start of volume) ;
         was already write access := TRUE
  FI .

erase archive :
  IF file in directory
    THEN IF is last file of archive
           THEN cut off all erased files
           ELSE rename to dummy
         FI
  FI .

file in directory :         dir index > 0 .

is last file of archive :   dir index = highest entry (directory) .

cut off all erased files :
  directory state := invalid ;
  REP
    delete (directory, dir index) ;
    dir index DECR 1
  UNTIL dir index = 0 COR name (directory, dir index) <> dummy name PER ;
  behind last valid file ;
  write end of volume ;
  directory state := valid .

behind last valid file :
  seek (header block (dir index + 1)) ;
  end of volume block := block number .

rename to dummy :
    directory state := invalid ;
    to file header ;
    read header ;
    to file header ;
    header.name := dummy name ;
    header.date := dummy date ;
    write (header space) ;
    rename (directory, file name, dummy name) ;
    header date (dir index) := dummy date ;
    directory state := valid .

to file header :
  seek (header block (dir index)) .

ENDPROC erase ;

PROC save (DATASPACE VAR ds) :

  IF file name <> dummy name
    THEN save to archive
    ELSE error ("Name unzulaessig")
  FI .

save to archive :
  IF file too large OR highest entry (directory) >= max files
    THEN error ( "kann nicht geschrieben werden (Archiv voll)")
    ELSE write new file
  FI .

file too large :
  end of volume block + ds pages (ds) + 5 > archive size .

write new file :
  seek (end of volume block) ;
  disable stop ;
  write file (ds) ;
  IF is error
    THEN seek (end of volume block)
    ELSE insert (directory, file name, dir index) ;
         remember begin of header block ;
         remember date
  FI ;
  write end of volume .

remember begin of header block :
  header block (dir index) := end of volume block .

remember date :
  header date (dir index) := date .

ENDPROC save ;

PROC write file (DATASPACE CONST ds) :

  enable stop ;
  write header (file name, date, file header) ;
  write (ds) 

ENDPROC write file ;

PROC write end of volume :

  disable stop ;
  end of volume block := block number ;
  write header ("", "", end of volume)

ENDPROC write end of volume ;

PROC write header (TEXT CONST name, date, INT CONST header type) :

  forget (header space) ;
  header space := nilspace ;
  header := header space ;

  header.name := subtext (name,1,100) ;
  header.date := date ;
  header.type := header type ;

  write (header space) 

ENDPROC write header ;

PROC read header :

  IF archive size > 0
    THEN forget (header space) ;
         header space := nilspace ;
         read (header space, 1, accept read errors) ;
         header := header space
    ELSE errorstop ("Lesen unmoeglich (Archiv)")
  FI .

ENDPROC read header ;

PROC simulate header (INT CONST type, TEXT CONST name) :

  forget (header space) ;
  header space := nilspace ;
  header := header space ;
  header.name := name ;
  header.date := "??.??.??" ;
  header.type := type ;
  header.password := ""

ENDPROC simulate header ;

PROC look at volume header :

  rewind ;
  archive size := archive blocks ;
  forget (header space) ;
  header space := nilspace ;
  INT VAR return code ;
  read block (header space, 1, 1, return code) ;
  header := header space ;
  disable stop ;
  IF return code <> 0 OR
     LENGTH header.name < 0 OR LENGTH header.name > 100 OR is error
    THEN header.name := "" ;
         clear error
  FI

ENDPROC look at volume header ;

PROC list (DATASPACE VAR ds) :

  access archive ;
  open list file ;
  INT VAR file number := 0 ;
  get (directory, file name, file number) ;
  WHILE file number > 0 REP
    generate list line ;
    get (directory, file name, file number)
  PER ;
  IF directory state = read only
    THEN putline (list file, "Lesefehler: Evtl. fehlen Eintraege")
  FI ;
  write list head .

open list file :
  forget (ds) ;
  ds := nilspace ;
  FILE VAR list file := sequential file (output, ds) ;
  putline (list file, "") .

generate list line :
  write (list file, header date (file number)) ;
  write (list file, text (file blocks DIV 2, 5)) ;
  write (list file, " K  ") ;
  IF file name = dummy name
    THEN write (list file, dummy name)
    ELSE write (list file, quote) ;
         write (list file, file name) ;
         write (list file, quote)
  FI ;
  line (list file) .

file blocks :
  IF file number < highest entry (directory)
    THEN header block (file number+1) - header block (file number)
    ELSE end of volume block - header block (file number)
  FI .

write list head :                                      (* wk 22.08.85 *)
  headline (list file, archive name +
            " (" + used + " K belegt von " + text (archive size DIV 2) + " K)") .

used :  text ((end of volume block + 3) DIV 2) .

ENDPROC list ;

PROC error (TEXT CONST error msg) :

  errorstop ("""" + file name + """ " + error msg)
 
ENDPROC error ;

ENDPACKET archive manager ;