%include "GDMR_H:FSysAcc.Inc"
%include "GDMR_H:Tree.Inc"
%include "GDMR_H:Dir.Inc"
%include "GDMR_H:IO_F.Inc"

%externalroutinespec fsys initialise

%systemroutinespec phex(%integer i)
%externalstring(127)%fnspec itos(%integer i, j)

%conststring(127) lost and found = "Drive_1";  !<<<<<<<<<<<
%owninteger directory ID = -1

%predicate check treeness(%integer ID)
   %integer token, flags, status
      status = B tree open by ID(nil, ID, 0, token, flags)
      %if status = 0 %start
         ! Checksum etc was OK, so assume it is a directory....
         status = B tree close(token, 1)
         %true
      %else
         ! Probably a dud checksum.  The file hasn't been opened
         %false
      %finish
%end


! File header formats & constants.

! Access definitions (conventionally ID > 0 for user, < 0 for group)
%recordformat header access fm(%integer ID, access)

%constinteger no        access =   0   { File is inaccessible
%constinteger read      access =   1   { File can be read
%constinteger modify    access =   2   { File can be modified
%constinteger append    access =   4   { File can be appended to
%constinteger exchange  access =   8   { File can be (extent) exchanged
%constinteger link      access =  16   { File can be (un)linked
%constinteger control   access =  32   { File attributes can be modified
%constinteger deny      access =  64   { Invert sense of access bits

%constinteger an altering access mode = modify access ! append access ! %c
                                        exchange access

%constinteger new owner access = read   access ! modify   access ! %c
                                 append access ! exchange access ! %c
                                 link   access ! control  access
%constinteger new local access = read access
%constinteger new world access = no access;  ! nil access -> local

%constinteger system ID = -1

! Flag word definitions
%constinteger overlapping        file  = 16_0002
%constinteger bad block          file  = 16_0004
%constinteger improperly closed  file  = 16_0008

%constinteger backup   required        = 16_0100
%constinteger archive  required        = 16_0200

%constinteger multiple references      = 16_40000000;  ! Pseudo-flag

! Extent definition
%recordformat extent fm(%integer start, size)


! Header definition
%constinteger non extent size = 8 + 2 + 2 + 12 + 8 + %c
                                12 + 12 + 16 + 4 + 2 + 2

%constinteger extent limit = (512 - non extent size) // 8
%constinteger access table size = extent limit;  ! One grows up, other down

%recordformat file header fm((%integer checksum, ID,
                              %short header refcount,
                              %short flags,
                              %integer owner, owner access, supervisor,
                              %integer world access, local access,
                              %integer creator, static ID, audit ID,
                              %integer created, modified, accessed,
                              %string(15) creation name,
                              %integer blocks used,
                              %short bytes in last block,
                              %short extent limit,
                              ( %record(header access fm)%array %c
                                    access(1 : access table size) %c
                            %or %record(extent fm)%array %c
                                    extent(1 : extent limit)) %c
                             ) %or %integerarray x(1 : 128))

! ID fields:
!     directory | partition | sequence | index
!       2 bits  |   6 bits  |  8 bits  | 16 bits

%constinteger index              part = 16_0000FFFF
%constinteger file ID            part = 16_00FFFFFF
%constinteger partition          part = 16_3F000000
%constinteger partition         shift = 24
%constinteger partition number   mask = partition part >> partition shift
%constinteger file ID            mask = 16_3FFFFFFF

%constinteger file sequence increment = 16_00010000

%owninteger partition mask = 0

%routine process one(%record(file header fm)%name fh)
   %owninteger sequence = 0
   %string(255) new name
   %integer status, ID
      ID = fh_ID ! partition mask
      phex(ID);  printstring(" created as ")
      printstring(fh_creation name)
      %if check treeness(ID ! partition mask) %start
         printstring(" directory?")
         ID = ID ! 16_40000000
         sequence = sequence + 1
         new name = fh_creation name . "_" . itos(sequence, 0)
         printstring(" insert as ");  printstring(new name)
         status = directory insert ID(nil, directory ID, new name, ID)
         %if status = 0 %start
            printstring(" OK")
         %else
            printstring(" error ");  write(status, 0)
         %finish
      %finish
      newline
%end

%begin
   %string(255) file
   %record(file header fm) fh
   %integer token = 0, size, flags, ID, i, bytes
      %on 3, 9 %start
         printstring(event_message);  newline
         L close file(nil, token, 0) %if token # 0
         %stop
      %finish
      L translate path(nil, lost and found, directory ID)
      printstring("Lost & found directory is ")
      phex(directory ID);  newline
      prompt("Partition: ");  read(ID)
      partition mask = ID << 24
      ID = partition mask ! 16_00010001
      printstring("File ID is ");  phex(ID);  newline
      byteinteger(addr(file)    ) = 5
      byteinteger(addr(file) + 1) = 2
      integer    (addr(file) + 2) = ID & 16_3FFFFFFF
      F validate pathnames = 1
      L open file(nil, file, 1, 0, -1, 0, token, size, flags)
      printstring("Opened as ");  phex(token)
      printstring(", size ");  write(size, 0)
      printstring(", flags ");  phex(flags);  newline
      fsys initialise
      i = 1;  ! Skip slot 1 (index file)
      %cycle
         L read block(nil, token, i, bytes, fh)
         process one(fh) %if fh_ID & 16_0000FFFF # 0
         i = i + 1
      %repeat
%end %of %program
