[comp.os.cpm] CP/M disk Directories

mwilson@pnet01.cts.COM (Marc Wilson) (03/11/88)

Ok, all you CP/M mavens, here's a good question for you.  Not anything earth-
shattering, or anything like that... just irritating.

The scenario:  Disk B: is a DSDD 48 tpi drive.  It uses 8-bit allocation
groups, so 16 groups can be allocated in one directory extent.  The group
size is 2k, so each extent can address 32k.  That, I have no problem with.
What I have problems with is how the damn files are represented in the
directory.  A short example session follows.

----------

B0:WORK>save 511 test.fil s			; create a file in 2 extents
						; minus 1 record
SAVE, Version 0.4 (loaded at B000H)
  TEST    .FIL saved
B0:WORK>
B0:WORK>stat test.fil				; check it out


 Recs  Bytes  Ext Acc
  511    64k    2 R/W B:TEST.FIL		; Ok, 511 recs in 2 extents
Bytes Remaining On B: 154k

B0:WORK>stat b:dsk:


    B: Drive Characteristics
 3120: 128 Byte Record Capacity
  390: Kilobyte Drive  Capacity
  128: 32  Byte Directory Entries
  128: Checked  Directory Entries
  256: Records/ Extent				; Wait!  How is this done?
   16: Records/ Block				; Isn't the RC byte limited to
   40: Sectors/ Track				; a maximum of 80h records?
    2: Reserved Tracks

; Ok, now we look at the directory...

B0:WORK>

DU3  B0? s5
Group = 00:04, Track = 2, Sector = 5, Physical Sector = 4              

DU3  B0? d
00  005A3830 444F5331  30444F43 01000001  |.Z80DOS10DOC....|
10  45464748 494A4B4C  4D000000 00000000  |EFGHIJKLM.......|
20  005A3830 444F5331  305A3830 00000004  |.Z80DOS10Z80....|
30  4F000000 00000000  00000000 00000000  |O...............|
40  005A3830 4454494D  455A3830 0000003E  |.Z80DTIMEZ80...>|
50  35363738 00000000  00000000 00000000  |5678............|
				vv-------------- extent #1?
				vv    vv-------- 80h records in this
				vv    vv         extent?
				vv    vv
60  00544553 54202020  2046494C 01000080  |.TEST    FIL....|
70  090A0B0C 0E0F101E  393A3B4E 5C5D5E5F  |........9:;N\]^_|

DU3  B0? +d
Group = 00:05, Track = 2, Sector = 6, Physical Sector = 5              
				vv-------------- extent #3?
				vv    vv-------- 7fh records in this
				vv    vv-------- extent?
				vv    vv
00  00544553 54202020  2046494C 0300007F  |.TEST    FIL....|
10  60616263 64656667  686E6F70 71727374  |`abcdefghnopqrst|
20  00444953 4B202020  20444F43 00000005  |.DISK    DOC....|
30  75000000 00000000  00000000 00000000  |u...............|
40  00434150 20202020  2046494C 00000000  |.CAP     FIL....|
50  00000000 00000000  00000000 00000000  |................|
60  E5E5E5E5 E5E5E5E5  E5E5E5E5 E5E5E5E5  |eeeeeeeeeeeeeeee|
70  E5E5E5E5 E5E5E5E5  E5E5E5E5 E5E5E5E5  |eeeeeeeeeeeeeeee|

----------

What the @#^&$ happened to extent #0?  I thought I'd have two sequential
extents, numbered zero and 1.  Instead, I get two extents, numbered 1 and
3.  The first one says it has 128 records in it, and the second says it has
127 records in it.  That's only 255 records.  Where'd the rest of 'em go?

And another oddity.  I've been playing with random files lately ( that's
how I got into this mess, trying to prove that BDOS did things the way
the manual says! ), and just for fun, I built a random file that only had
records 0 and 0ffffh in it.  Lowest and highest.  Now, utilities like copy
programs and the like can't deal with this, because there are holes in the
allocation.  I see that.  But the directory above looks like it has holes in
the allocation as well!  Yet PIP/ACOPY/PIPE et. al. can read and copy *this*
file, *correctly*!

What's going on here?!


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Marc Wilson
     ARPA: ...!crash!mwilson@nosc.mil
           ...!crash!pnet01!pro-sol!mwilson@nosc.mil
     UUCP: [ cbosgd | hp-sdd!hplabs | sdcsvax | nosc ]!crash!mwilson
     INET: mwilson@crash.CTS.COM
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

mwilson@crash.cts.com (Marc Wilson) (03/12/88)

Ok, all you CP/M mavens, here's a good question for you.  Not anything earth-
shattering, or anything like that... just irritating.

The scenario:  Disk B: is a DSDD 48 tpi drive.  It uses 8-bit allocation
groups, so 16 groups can be allocated in one directory extent.  The group
size is 2k, so each extent can address 32k.  That, I have no problem with.
What I have problems with is how the damn files are represented in the
directory.  A short example session follows.

----------

B0:WORK>save 511 test.fil s			; create a file in 2 extents
						; minus 1 record
SAVE, Version 0.4 (loaded at B000H)
  TEST    .FIL saved
B0:WORK>
B0:WORK>stat test.fil				; check it out


 Recs  Bytes  Ext Acc
  511    64k    2 R/W B:TEST.FIL		; Ok, 511 recs in 2 extents
Bytes Remaining On B: 154k

B0:WORK>stat b:dsk:


    B: Drive Characteristics
 3120: 128 Byte Record Capacity
  390: Kilobyte Drive  Capacity
  128: 32  Byte Directory Entries
  128: Checked  Directory Entries
  256: Records/ Extent				; Wait!  How is this done?
   16: Records/ Block				; Isn't the RC byte limited to
   40: Sectors/ Track				; a maximum of 80h records?
    2: Reserved Tracks

; Ok, now we look at the directory...

B0:WORK>

DU3  B0? s5
Group = 00:04, Track = 2, Sector = 5, Physical Sector = 4              

DU3  B0? d
00  005A3830 444F5331  30444F43 01000001  |.Z80DOS10DOC....|
10  45464748 494A4B4C  4D000000 00000000  |EFGHIJKLM.......|
20  005A3830 444F5331  305A3830 00000004  |.Z80DOS10Z80....|
30  4F000000 00000000  00000000 00000000  |O...............|
40  005A3830 4454494D  455A3830 0000003E  |.Z80DTIMEZ80...>|
50  35363738 00000000  00000000 00000000  |5678............|
				vv-------------- extent #1?
				vv    vv-------- 80h records in this
				vv    vv         extent?
				vv    vv
60  00544553 54202020  2046494C 01000080  |.TEST    FIL....|
70  090A0B0C 0E0F101E  393A3B4E 5C5D5E5F  |........9:;N\]^_|

DU3  B0? +d
Group = 00:05, Track = 2, Sector = 6, Physical Sector = 5              
				vv-------------- extent #3?
				vv    vv-------- 7fh records in this
				vv    vv-------- extent?
				vv    vv
00  00544553 54202020  2046494C 0300007F  |.TEST    FIL....|
10  60616263 64656667  686E6F70 71727374  |`abcdefghnopqrst|
20  00444953 4B202020  20444F43 00000005  |.DISK    DOC....|
30  75000000 00000000  00000000 00000000  |u...............|
40  00434150 20202020  2046494C 00000000  |.CAP     FIL....|
50  00000000 00000000  00000000 00000000  |................|
60  E5E5E5E5 E5E5E5E5  E5E5E5E5 E5E5E5E5  |eeeeeeeeeeeeeeee|
70  E5E5E5E5 E5E5E5E5  E5E5E5E5 E5E5E5E5  |eeeeeeeeeeeeeeee|

----------

What the @#^&$ happened to extent #0?  I thought I'd have two sequential
extents, numbered zero and 1.  Instead, I get two extents, numbered 1 and
3.  The first one says it has 128 records in it, and the second says it has
127 records in it.  That's only 255 records.  Where'd the rest of 'em go?

And another oddity.  I've been playing with random files lately ( that's
how I got into this mess, trying to prove that BDOS did things the way
the manual says! ), and just for fun, I built a random file that only had
records 0 and 0ffffh in it.  Lowest and highest.  Now, utilities like copy
programs and the like can't deal with this, because there are holes in the
allocation.  I see that.  But the directory above looks like it has holes in
the allocation as well!  Yet PIP/ACOPY/PIPE et. al. can read and copy *this*
file, *correctly*!

What's going on here?!
-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Marc Wilson
     ARPA: ...!crash!mwilson@nosc.mil
           ...!crash!pnet01!pro-sol!mwilson@nosc.mil
     UUCP: [ cbosgd | hp-sdd!hplabs | sdcsvax | nosc ]!crash!mwilson
     INET: mwilson@crash.CTS.COM
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

cwwj@ur-tut.UUCP (Clarence Wilkerson) (03/13/88)

I'm a little rusty at this, but let try any way. Here's an explanation
that seems to fit your observations:
1) The number of extents controlled by a single directory entry is 2
16k extents.
2) The total number of sectors covered by a single directory entry is
at most 80h in RC + 1*80h from the extent byte.
3) Thus your 2 directory entries cover 256 sectors for first entry
and 255 for second = 511.
  That is, the first directory entry in your system will have an extent
byte 0 if you have 80h or fewer sectors in the file. If you have between
81h and 256 sectors, the extent byte is 1, and the RC byte is the rest.

n
I'm a little rusty, but here's an exp

dick_a_wotiz@cup.portal.com (03/14/88)

> Ok, all you CP/M mavens, here's a good question for you.  Not anything earth-
> shattering, or anything like that... just irritating.
> 
>  . . . .
> 
>                                 vv-------------- extent #1?
>                                 vv    vv-------- 80h records in this
>                                 vv    vv         extent?
>                                 vv    vv
> 60  00544553 54202020  2046494C 01000080  |.TEST    FIL....|
> 70  090A0B0C 0E0F101E  393A3B4E 5C5D5E5F  |........9:;N\]^_|
> 
>                                 vv-------------- extent #3?
>                                 vv    vv-------- 7fh records in this
>                                 vv    vv-------- extent?
>                                 vv    vv
> 00  00544553 54202020  2046494C 0300007F  |.TEST    FIL....|
> 10  60616263 64656667  686E6F70 71727374  |`abcdefghnopqrst|

   Actually, the byte you are calling the 'extent #' is handled a
little differently.  The LSB of this byte means 'add 80h records to
the record count byte', and the upper 7 bits, when shifted once to
the right, are the extent number.

   The '# of records' byte is never allowed to get larger than 80h,
so this method is needed to allow up to 256 records per extent.

Some examples:                    vv    vv
      extent 0,  127 records:     0000007F
         "       128 records:     00000080
         "       129 records:     01000001
         "       256 records:     01000080
      extent 1,  1   record:      02000001
         "       129 records:     03000001
         "       255 records:     0300007F

- - - - - - - - - - - - - - - - - - - - - -
     dick@portal.com                {uunet|sun|atari}!portal!dick
     dick@cup.portal.com

Robert_A_Freed@cup.portal.com (03/14/88)

In message <2662@crash.cts.com> mwilson@crash.cts.com (Marc Wilson)
writes in some detail about a 511-record file (just short of 64K
bytes), which uses two directory entries on a floppy disk system with
2K-byte allocation block size (32K-byte extent size).

> What's going on here?!

What's going on is that you are confused about the RC (record count)
and EX (extent number) bytes in a directory entry.  This is
understandable, since the DRI (Digital Research, Inc.) CP/M 2.2
documentation only describes the CP/M 1.x case of 1K allocation
blocks and 16K extents.

In order to accommodate larger disk capacities, DRI altered the
meaning of these bytes in CP/M version 2.  They did this in a way
which is downward compatible with CP/M version 1.  The record count
for an extent is now split between the low 7 bits of RC and the lower
bits of EX.  The portion of EX which is used for the high part of the
record count is specified by the "extent mask."  A full extent is
still indicated by RC = 80h (with all extent mask bits in EX set).
I.e., the high bit of RC serves as a flag rather than as part of the
record count.  The true "extent number" is obtained by right-shifting
EX by the number of bits in the extent mask.

> What the @#^&$ happened to extent #0?  I thought I'd have two sequential
> extents, numbered zero and 1.  Instead, I get two extents, numbered 1 and
> 3.  The first one says it has 128 records in it, and the second says it has
> 127 records in it.  That's only 255 records.  Where'd the rest of 'em go?

In your case, the extent mask is 1.  The two EX bytes (01h and 03h)
become 0 and 1 after shifting right by one bit.  The RC value (80h)
for the first extent indicates it is full (256 records).  The RC
value (7Fh) for the second extent is combined with the low bit of the
EX value to yield record count FFh (255 records).  This is as you had
expected.  No records are "lost" and the file is not "sparse" (no
unallocated extents.)

Note:  The above description is sufficient for disks with no more
than 512K-byte capacity.  However, two additional details must be
noted to completely describe the situation for larger capacity disks.
First, the upper 3 bits of the EX byte are always zero.  (The reason
for this is somewhat obscure:  Since EX participates in directory
scans by BDOS functions such as Open_File and Search_for_First, a
valid EX value must not match 3Fh, the ASCII code for the ? character
used as a "wildcard.")  Second, because the remaining 5 EX bits
(less, due to the extent mask) are insufficient for specifying all
extent numbers, the upper bits of the extent number overflow into the
S2 byte, which was unused in CP/M version 1.

To me, it's always seemed a shame that DRI went to such lengths to
preserve backward compatibility with older versions of CP/M and then
failed to properly document the changes.  I was only able to fully
understand the above by disassembling BDOS (many, many moons ago).
And I have seen many public domain programs that manipulate directory
entries break on hard disk systems due to a lack of understanding of
these details.

Bob Freed

Internet:  Robert_A_Freed@cup.portal.com
Uucp: ...!sun!portal!cup.portal.com!Robert_A_Freed