! Filestore copier -- reading program

%option "-low-nonstandard"

%include "System:Config.Inc";  ! For disc layout of source filestore
%include "System:DisqIO.Inc"

%include "Formats.Inc"
%include "Utility.Inc"

%include "Inc:FS.Imp"
%include "Inc:Util.Imp"

! Ether stuff

%constinteger port = 15
%constinteger mask = 1 << port
%constinteger timeout time = 30 000

%routine initialise ether
   %integer writer
      prompt("Writer: ");  rhex(writer)
      ether open(port, writer << 8 ! port)
%end

%routine send message(%record(message fm)%name m)
   %owninteger sequence = 0
   %record(message fm) reply
   %integer n, bored
      sequence = sequence + 1
      m_sequence = sequence
      %cycle
         NAK = 0
         ether write(port, byteinteger(addr(m)), message size)
         %cycle;  %repeat %until ACK & mask # 0
         %exit %if NAK & mask = 0
         printstring("NAK");  newline
      %repeat
      bored = CPU time + timeout time
      %cycle
         %if dtx & mask # 0 %start
            n = ether read(port, byteinteger(addr(reply)), message size)
            %if reply_sequence = m_sequence %start
               %if reply_code < 0 %start
                  printstring("Reply ");  write(reply_sequence, 0)
                  printstring(" code ");  write(reply_code, 0)
                  newline
               %finish
               %return
            %finish
         %finish
         %if CPU time > bored %start
            printstring("Timeout message ");  write(sequence, 0)
            newline
            %return
         %finish
      %repeat
%end
      

%ownrecord(directory fm) current directory

%routine get directory(%integer partition, slot)
   ! Read specified directory from disc slot (0 .. 127)
   %integername x
      x == transfer(d read ! d verify, 2048,
                    (pd start(partition) + 4 * slot) << 9,
                    integer(addr(current directory)))
      %cycle;  %repeat %until x # 0
      current directory = 0 %if x # 2048
%end

%routine send directory(%integer partition)
   %integer i, j, k, block, previous extents, files
   %record(header fm)%name h
   %record(entry fm)%name f
   %record(extent fm)%name e
   %record(message fm) message
   %integername x
      h == current directory_header
      %return %if h_owner = 0;  ! Unused
      message_new user = h
      message_partition = partition
      message_code = create user
      send message(message)
      files = h_files & files mask
      %return %if files = 0
      previous extents = extent limit + 1
      %for i = 1, 1, files %cycle
         f == current directory_file(i)
         printstring("Sending ")
         printstring(unpack(h_owner, 0))
         print symbol(':')
         printstring(unpack(f_name 1, f_name 2))
         print symbol('?') %if f_status & dud file # 0
         print symbol('!') %if f_status & transient file # 0
         newline
         message_new file = f
         message_code = create file
         send message(message)
         block = 0
         %for j = previous extents - 1, -1, f_extents %cycle
            e == current directory_extent(j)
            %for k = 1, 1, e_size %cycle
               block = block + 1
               x == transfer(d read ! d verify, 512,
                             (p start(partition) + (e_start & hh) + k - 1) << 9,
                             integer(addr(message_data(0))))
               %while x = 0 %cycle;  %repeat
               %if x # 512 %start
                  printstring("Error reading block ")
                  write(block, 0);  newline
               %finish
               %if k = e_size %and j = f_extents %start
                  ! Last block of file.  Note short size
                  message_bytes = f_bytes & bytes mask
               %else
                  ! Not last, must be full size
                  message_bytes = 512
               %finish
               message_block = block
               message_code = write block
               send message(message)
            %repeat
         %repeat
         message_block = block
         message_bytes = -1
         message_code = write block
         send message(message)
         previous extents = f_extents
      %repeat
%end

%begin
   %integer p, n, start p, end p
   %record(message fm) m
      set terminal mode(no page)
      initialise ether
      prompt("Start partition: ")
      read(start p) %until 0 <= start p <= last partition
      prompt("End partition: ")
      read(end p) %until start p <= end p <= last partition
      %for p = start p, 1, end p %cycle
         %for n = 0, 1, 127 %cycle
            get directory(p, n)
            send directory(p)
         %repeat
      %repeat
      ! Close down by sending a null create
      m = 0
      m_code = create user
      send message(m)
%end %of %program
