[comp.os.cpm] file truncation in CP/M 2.2?

bridger%newton@RAND-UNIX.ARPA (Bridger Mitchell) (06/01/88)

Unlike CP/M Plus, CP/M 2.2 has no truncate-file function.  This
is a useful function when a large file (e.g. a database or library file)
needs to be "lopped off", or packed down, and there's a lack of disk
space to create a temporary duplicate file.

Is there a portable method of truncating a CP/M 2.2 file, using only
BDOS calls?  I believe the following approach will work so long as the
shorter file's final physical extent (i.e. directory entry) is the
same as the original file's:

	open the file
	get file size, to set extent, S2, and record count bytes
	change record count to new number of records in final
	  logical extent
	change extent number, if necessary, to new final logical
	  extent
	clear bit 7 of S2, to mark the file/fcb "modified"
	close the file
	use function 37 to log off the drive (use the FRESET routine,
	  or function 13, if run on the buggy DRI BDOS).

The BDOS will write the changed fcb (directory entry) to the directory
when the file is closed, then rebuild the allocation vector for the
drive using the new number of records.

BUT...what can be done if the truncation results in eliminating the
last physical extent(s)?  The BDOS internally opens and closes each
physical extent of a multi-extent file.  Suppose, for example, you read
randomly the last record you wish to keep in the new file and  it's
not in the last physical extent.  Then you use the procedure above,
and the intermediate extent will be modified in the directory.

But the final extent will remain in the directory, unchanged.  Disk
logins will continue to keep the data groups reserved in that entry
allocated; they are effectively stranded.  And directory utilities
that sort extents will be badly confused.  You'd like to "erase" just
that final extent.  But this can't be done by BDOS calls.  Or can it?

-- bridger mitchell

dg@lakart.UUCP (David Goodenough) (06/02/88)

From article <8806010017.AA28247@newton.arpa>, by bridger%newton@RAND-UNIX.ARPA (Bridger Mitchell):
> 
> Unlike CP/M Plus, CP/M 2.2 has no truncate-file function.  This
> is a useful function when a large file (e.g. a database or library file)
> needs to be "lopped off", or packed down, and there's a lack of disk
> space to create a temporary duplicate file.
> 
> Is there a portable method of truncating a CP/M 2.2 file, using only
> BDOS calls?

[description of how to do it]

Yes - changing the file size (.fcb + 0fh) will do what you want - this is
how xsub works.

> BUT...what can be done if the truncation results in eliminating the
> last physical extent(s)?
> ..... But this can't be done by BDOS calls.  Or can it?

No it can't. but it CAN be done portably with BIOS calls. By inspecting
the bios tables (use the "get dpb address" function from bdos) you can
figure out exactly where the directory is, and how big it is. Now keep
on reading directory sectors using bios till you hit the one with the
extent that you want to nuke. Now just replace the first byte in the 32
byte entry with 0e5h, write it back (see caveat) and voila!
CAVEAT: whatever you do, when you write this sector back, reuse the
bios select disk, track, and sector routines, AND MAKE SURE C CONTAINS 1.
At least one bios I've seen destroys the track/sector info on each
read/write, so it's a good idea to reset them. Setting C to 1 forces
the write to happen: usually on bioses where the sector size is
greater than 128 bytes (i.e. all 5.25" DD versions) when a write happens,
the data is just buffered, and only gets flushed when another write to a
different sector occurs. By making C == 1, it forces the bios to write,
hence the directory is kept up to date.

Easy Huh? :-) :-)
-- 
	dg@lakart.UUCP - David Goodenough		+---+
							| +-+-+
	....... !harvard!adelie!cfisun!lakart!dg	+-+-+ |
						  	  +---+