// IfsBackupUtil.bcpl -- Utilities for backup process
// Copyright Xerox Corporation 1979, 1981, 1982

// Last modified September 17, 1982  10:47 AM by Taft

get "Ifs.decl"
get "IfsFiles.decl"
get "IfsBackup.decl"
get "IfsDirs.decl"
get "BTree.decl"

external
[
// outgoing procedures
BackupIFSDir

// incoming procedures
CopyFile; EmptiestFreePages; GetDiskFromFD; GetBufferForFD
LookupIFSFile; LookupFD; CreateFD; NextFD; DestroyFD; UnlockDirFD
TransferLeaderPage; CreateIFSFile; IFSDeleteOldVersions
FlushBTreeState; FlushBuffers; IFSError
SysAllocate; SysFree
]

//---------------------------------------------------------------------------
let BackupIFSDir(fs, backupFS) = valof
//---------------------------------------------------------------------------
// Backs up <System>IFS.Dir from fs onto the next higher version of
// <System>BackupIFS.Dir on backupFS, then deletes all previous versions.
// Returns true normally and false if the backup file system is full.
[
let ec = nil

// Lookup IFS.Dir in fs and read-lock the directory
// so it can't change out from under us.
let fd = LookupIFSFile("<System>IFS.Dir!1", 0, lv ec, fs)
if fd eq 0 then IFSError(ecCantFindIFSDir, ec)
LookupFD(fd, lockRead)
FlushBTreeState()  //ensure disk state is consistent
FlushBuffers(true)

// Ensure there is enough room in the backup file system.
let pages = fs>>IFS.dirBTree>>TREE.GreatestPage+2
if EmptiestFreePages(backupFS) uls pages+100 then
   [ UnlockDirFD(fd); DestroyFD(fd); resultis false ]

// Create next higher version of backup directory file
let backupName = "<System>BackupIFS.Dir"
let backupFD = CreateFD(backupName, lcVNext+lcCreate, lv ec, backupFS)
if backupFD ne 0 then ec = LookupFD(backupFD, lockWrite)
if ec ne 0 then IFSError(ecBackupLookupFile, ec)
let buf = GetBufferForFD(backupFD)
TransferLeaderPage(fd, buf)
buf>>ILD.undeletable = false
ec = CreateIFSFile(backupFD, buf)
if ec ne 0 then IFSError(ecBackupCreateFile, ec)
UnlockDirFD(backupFD)
SysFree(buf)  //don't hold on to buf across CopyFile call

// Actually copy the file to the backup disk
CopyFile(GetDiskFromFD(backupFD), lv backupFD>>FD.dr>>DR.fp,
 GetDiskFromFD(fd), lv fd>>FD.dr>>DR.fp, 0, pages, true)

// Unlock primary directory and clean up
UnlockDirFD(fd)
DestroyFD(fd)
DestroyFD(backupFD)

// Delete obsolete versions of BackupIFS.Dir
IFSDeleteOldVersions(backupName, 0, backupFS)
resultis true
]