.alone←declaration(expurgate)=0;
.if alone then start
.require "ttydefs.pub" source!file
.end
.every heading (|DiskFindHole|,|July 26, 1982|,{page})
.once center
DiskFindHole
.skip 3

The procedure DiskFindHole, in DiskFindHole.br, can be used to locate a "hole" of available space in the disk bit table.  This procedure works with any type of disk object (BFS or TFS).  The call:

.once indent 4
virtualDA = DiskFindHole(disk, nPages)

will attempt to locate a contiguous hole nPages long.  If it succeeds, it returns the virtual disk address of the first page of the hole; if it fails, it returns eofDA (defined in Disks.d).

The call:

.once indent 4
virtualDA = DiskFindHole(disk, nPages, lv holeSize)

will operate as described above if a hole of size nPages actually exists, and additionally will store nPages in holeSize.  However, if there is no hole sufficiently large, it will locate the largest hole, store the actual size of that hole in holeSize, and return the virtual disk address of the first page of the hole.  (In this type of call, eofDA will be returned only if the disk is entirely full.)

In order to create a contiguous file, it is first necessary to create the minimal file with a leader page at the given disk address, and then to extend the file to fill the hole.  The first step is begun by calling:

.once indent 4
ReleaseDiskPage(disk, AssignDiskPage(disk, virtualDA-1))

where virtualDA is the desired disk address (i.e., the result returned by DiskFindHole).  This operation will control the selection of a disk address for the next free-choice allocation.  The file is then created by means such as:

.begin nofill indent 4 skip 1
let s = OpenFile("Contiguous.file", ksTypeWriteOnly, 0, verNew,
   0, 0, 0, 0, 0, disk)
PositionPage(s, nPages-1)
.end

Once the file is created, it is wise to extend it to its final length immediately, else other disk allocations might encroach on the hole that was located.

Note that the correctness of the result returned by DiskFindHole depends on the accuracy of the disk bit table, which, strictly speaking, is only a hint.  Applications that require a file to be contiguous must check explicitly after creating it.  For example:

.begin nofill indent 4 skip 1
let cfa = vec lCFA
FileLength(s)
GetCompleteFa(s, cfa)
unless cfa>>CFA.fp.leaderVirtualDA eq virtualDA &
 cfa>>CFA.fa.da eq virtualDA+nPages-1 do
   [ ... file is not contiguous ... ]
.end