.\" Believe it or not, reportedly there are nroffs which do not know \(en
.if n .ds en -
.if t .ds en \(en
-.TH CPM 5 "November 26, 2007" "CP/M tools" "File formats"
+.TH CPM 5 "October 10, 2022" "CP/M tools" "File formats"
.SH NAME \"{{{roff}}}\"{{{
cpm \- CP/M disk and file system format
.\"}}}
.br
Logical sector skew
.br
-Number of reserved system tracks
+Number of reserved system tracks (optional)
+.br
+Offset to start of volume (optional and not covered by operating system,
+but disk driver specific)
.sp
.RE
A block is the smallest allocatable storage unit. CP/M supports block
sizes of 1024, 2048, 4096, 8192 and 16384 bytes. Unfortunately, this
format specification is not stored on the disk and there are lots of
formats. Accessing a block is performed by accessing its sectors, which
-are stored with the given software skew.
+are stored with the given software skew. \fBcpmtools\fP always counts
+sectors starting with 0, as it deals with logical sectors. CP/M uses physical
+sectors in the skew table, which often start with 1.
.\"}}}
.SS "Device areas" \"{{{
-A CP/M disk contains three areas:
+A CP/M disk contains four areas:
.RS
.sp
+Volume offset (optional and not covered by operating system, but disk driver specific)
+.br
System tracks (optional)
.br
Directory
The term \fIdisk capacity\fP always excludes the space for system tracks.
Note that there is no bitmap or list for free blocks. When accessing a
drive for the first time, CP/M builds this bitmap in core from the directory.
+.LP
+A hard disk can have the additional notion of a \fIvolume offset\fP to
+locate the start of the drive image (which may or may not have system
+tracks associated with it). The base unit for volume offset is byte
+count from the beginning of the physical disk, but specifiers of
+\fIK\fP, \fIM\fP, \fIT\fP or \fIS\fP may be appended to denote
+kilobytes, megabytes, tracks or sectors. If provided, a specifier
+must immediately follow the numeric value with no whitespace. For
+convenience upper and lower case are both accepted and only the first
+letter is significant, thus 2KB, 8MB, 1000trk and 16sec are valid
+values. The \fBoffset\fP must appear subsequent to track, sector and sector
+length values for the sector and track units to work.
+.LP
+Note that it is possible to reserve space between the directory and
+the beginning of data. Although typically data follows the directory,
+some systems used this to store extra data instead of using more
+system tracks (see the fields \fBALV0\fP and \fBALV1\fP in the
+DPB).
+.LP
+There are disk formats that map multiple logical tracks onto a physical
+track, which allows a little bit more capacity in case the system image
+size does not match the physical track capacity well.
.\"}}}
.SS "Directory entries" \"{{{
The directory is a sequence of directory entries (also called extents),
\fBSt\fP is the status; possible values are:
.RS
.sp
-0\*(en15: used for file, status is the user number
+0\*(en15: used for file, status is the user number. CP/M 2.2 only documents
+0\*(en15 and CCP and PIP only offer those, but the BDOS allows to use 0\*(en31.
.br
-16\*(en31: used for file, status is the user number (P2DOS)
+16\*(en31: used for file, status is the user number (P2DOS, CP/M 2.2)
or used for password extent (CP/M 3 or higher)
.br
32: disc label
Rc stores the number of 128 byte records of the last used logical extent.
Bc stores the number of bytes in the last used record. The value 0 means
128 for backward compatibility with CP/M 2.2, which did not support Bc.
+ISX records the number of unused instead of used bytes in Bc.
+This only applies to files with allocated blocks. For an empty file, no
+block is allocated and Bc 0 has no meaning.
.\"}}}
.LP
.\"{{{ Al = allocated blocks
-\fBAl\fP stores block pointers. If the disk capacity is less than 256 blocks,
-Al is interpreted as 16 byte-values, otherwise as 8 double-byte-values.
-A block pointer of 0 marks a hole in the file. If a hole
-covers the range of a full extent, the extent will not be allocated. In particular,
-the first extent of a file does not neccessarily have extent number 0.
-A file may not share blocks with other files, as its blocks would be freed
-if the other files is erased without a following disk system reset. CP/M returns
-EOF when it reaches a hole, whereas UNIX returns zero-value bytes, which makes
-holes invisible.
+\fBAl\fP stores block pointers. If the disk capacity minus boot
+tracks but including the directory area is less than or equal to 256 blocks, Al
+is interpreted as 16 byte-values, otherwise as 8 double-byte-values.
+Since the directory area is not subtracted, the directory area starts
+with block 0 and files can never allocate block 0, which is why this
+value can be given a new meaning: A block pointer of 0 marks a hole in
+the file. If a hole covers the range of a full extent, the extent will
+not be allocated. In particular, the first extent of a file does not
+neccessarily have extent number 0. A file may not share blocks with other
+files, as its blocks would be freed if the other files is erased without
+a following disk system reset. CP/M returns EOF when it reaches a hole,
+whereas UNIX returns zero-value bytes, which makes holes invisible.
.\"}}}
.\"}}}
-.SS "Time stamps" \"{{{
+.SS "Native time stamps" \"{{{
P2DOS and CP/M Plus support time stamps, which are stored in each fourth
directory entry. This entry contains the time stamps for
the extents using the previous three directory entries. Note that you
1 byte minute in BCD format
.sp
.RE
+All time stamps are stored in local time.
+.\"}}}
+.SS "DateStamper time stamps" \"{{{
+The DateStamper software added functions to the BDOS to manage
+time stamps by allocating a read only file with the name "!!!TIME&.DAT"
+in the very first directory entry, covering the very first data
+blocks. It contains one entry per directory entry with the
+following structure of 16 bytes:
+.RS
+.sp
+5 bytes create datefield
+.br
+5 bytes access datefield
+.br
+5 bytes modify datefield
+.br
+1 byte magic number/checksum
+.sp
+.RE
+The magic number is used for the first 7 entries of each 128-byte record
+and contains the characters \fB!\fP, \fB!\fP, \fB!\fP, \fBT\fP, \fBI\fP,
+\fBM\fP and \fBE\fP. The checksum is used on every 8th entry (last entry
+in 128-byte record) and is the sum of the first 127 bytes of the record.
+Each datefield has this structure:
+.RS
+.sp
+1 byte BCD coded year (no century, so it is sane assuming any year < 70
+means 21st century)
+.br
+1 byte BCD coded month
+.br
+1 byte BCD coded day
+.br
+1 byte BCD coded hour or, if the high bit is set, the high byte of a
+counter for systems without real time clock
+.br
+1 byte BCD coded minute, or the low byte of the counter
+.sp
+.DE
.\"}}}
.SS "Disc labels" \"{{{
CP/M Plus support disc labels, which are stored in an arbitrary directory