// IFSCreate1.bcpl -- code for creating an Interim File System
//	This portion must be resident during Primary IFS creation
// Copyright Xerox Corporation 1979

// Last modified July 14, 1979  9:07 PM by Taft

get "ifs.decl"
get "ifsfiles.decl"
get "disks.d"
get "tfs.d"
get "ifsdirs.decl"
get "streams.d"

// Outgoing procedures
CreateIFSPart1; CreateIFSDisk; OpenSystemFile

// Incoming procedures
TFSNewDisk; TFSInit; TFSClose; TFSDiskModel; AssignDiskPage; ReleaseDiskPage
Allocate; Free; MoveBlock; Zero; ReadCalendar; CopyString
OpenFile; WriteBlock; Closes; SysErr; IFSError
FileLength; PositionPage

// Incoming statics
let CreateIFSPart1(cPar) = valof
//Performs the first part of IFS creation.  It calls only those
//procedures that are resident at initialization time so as to permit
//creating a primary IFS.  Specifically, it creates a virgin Alto file
//system on each pack and creates all the system files.  When it is done,
//it TFSCloses all units it has TFSInited, and it does not touch
//the system physical-logical disk table, so the caller is expected
//to do an OpenIFSPart1 before calling CreateIFSPart2.
//Returns zero if successful and an error code if unsuccessful.
//build home block
let home = Allocate(sysZone, lenHome)
Zero(home, lenHome)
home>>Home.type = cPar>>CPar.type
home>>Home.numUnits = cPar>>CPar.numUnits
ReadCalendar(lv home>>Home.created)
CopyString(lv home>>Home.id, cPar>>CPar.id)
CopyString(lv home>>Home.name, cPar>>CPar.name)

// Check all the drives to make sure they are there and
// to see whether they are T-300s
for unit = 0 to cPar>>CPar.numUnits-1 do
   let disk = TFSInit(sysZone, false, cPar>>CPar.lpMap↑unit, 0, true)
   if disk eq 0 then [ Free(sysZone, home); resultis ecNotOnLine ]
   if TFSDiskModel(disk) eq 300 then
      [  // Add a logical unit for the second half of this T-300
      cPar>>CPar.lpMap↑(home>>Home.numUnits) = #400 + cPar>>CPar.lpMap↑unit
      home>>Home.numUnits = home>>Home.numUnits+1

//do the initialization for each logical unit
let res = nil
for unit = 0 to home>>Home.numUnits-1 do
   res = CreateIFSDisk(unit, cPar>>CPar.lpMap↑unit, home, cPar>>CPar.dirSize)
   if res ne 0 break

Free(sysZone, home)
resultis res
and CreateIFSDisk(unit, drive, home, dirSize) = valof
// Initializes logical unit of an IFS.  Returns zero if successful and an
// error code if unsuccessful.  Drive may be #400+drive# to designate the
// second half of a T-300.  dirSize is the number of pages to preallocate
// for IFS.dir; needed only if unit=0.
// Erase the disk
unless TFSNewDisk(sysZone, drive) resultis ecCantTFSNewDisk

// Create IFS.Home.
// Allocate system files next to the DD in the middle of the disk.
let disk = TFSInit(sysZone, true, drive)
if disk eq 0 resultis ecCantTFSInit
ReleaseDiskPage(disk, AssignDiskPage(disk, disk>>TFSDSK.VDAdiskDD↑1))
let str = OpenSystemFile(disk, "IFS.Home")
home>>Home.thisUnit = unit
WriteBlock(str, home, lenHome)

// If this is logical unit 0, create IFS.Dir.
// If unit 0 of a primary IFS, create other system files also.
if unit eq 0 then
   CreateSystemFile(disk, "IFS.Dir", dirSize)
   if home>>Home.type eq ifsTypePrimary then
      CreateSystemFile(disk, "IFS.Swap", ifsSwapPages)
      CreateSystemFile(disk, "IFS.Errors", ifsErrorPages)
      CreateSystemFile(disk, "IFS.Syms", ifsSymsPages)
ReleaseDiskPage(disk, AssignDiskPage(disk, 0))
resultis 0

and CreateSystemFile(disk, name, pages) be
//Creates a blank file of the specified length (in pages)
let str = OpenSystemFile(disk, name)
PositionPage(str, pages)

and OpenSystemFile(disk, name) = valof
let str = OpenFile(name, 0, 0, 0, 0, 0, 0, 0, disk)
if str eq 0 then IFSError(ecCreateEssentialFile, name)
resultis str