Date: 12 Mar 88 01:51:27 GMT From: hubcap!ncrcae!ncr-sd!crash!mwilson@gatech.edu (Marc Wilson) Subject: CP/M disk Directories 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ------------------------------ Date: Mon 14 Mar 1988 11:46:02 EDT From: <SAGE@LL.ARPA> Subject: CP/M Directory Entries This is the classic problem of logical vs physical. In one case 'extent' is used to refer to the contents of one directory entry (32K or 256 logical records -- physical records probably only 32 or 64!). The logical extent is always 16K, and thus there can be two logical extents in one physical extent, just as there can be 2 or 4 or 8 logical records (128 bytes) in each physical record. The extent number in the directory entry is the number of the last extent in that directory, and the record count is the number of logical records in that last extent. With larger block sizes on a hard disk it is quite possible to have 4 or probably even 8 logical extents per physical extent. The same rules apply. ------------------------------ Date: Mon, 14 Mar 88 12:01:05 PST From: Bridger Mitchell <bridger%rcc@rand-unix.ARPA> Subject: CP/M directory extents Yes, directory calculations are confusing, and not helped by confusing terminology! The key point is to keep physical and logical extents distinct. A CP/M LOGICAL extent holds 16K, or 80h = 128 records (each 128 bytes). A CP/M file can have several directory entries. Each DIRECTORY ENTRY (i.e. 32 bytes in the first group(s) on a disk) has 16 bytes of space for data group numbers; the group numbers must be words if there are >255 groups on a disk. Thus: A CP/M PHYSICAL extent (i.e., a single DIRECTORY ENTRY) may be hold a multiple of 16K. The multiple depends on: (a) whether a group number is a byte or word (b) the size of one allocation group (1,2,4,8,16 K) (c) whether the format designer used all of the 16 bytes available in a single directory entry The RECORD COUNT BYTE gives the number of records in the HIGHEST logical extent referenced by the physical extent/directory entry it appears in. Similarly, the EXTENT BYTE (and its overflow into the low-order bits of the S2 byte) gives the number of the HIGHEST logical extent referenced by the physical extent/directory entry it appears in. examples: (with S2 and EXT appropriately masked to remove internal bdos flag bits) #1 S2 = 0, EXT = 1, RC = 7fh If there is 1 directory entry per logical extent, then this is the second directory entry; its final record is 7f=127. If there are 2 or more directory entries per logical extent this is the first directory entry; its final record is 80h + 7fh = 255. #2 S2 = 0, EXT =1, RC = 80h If there is 1 directory entry per logical extent, then this is the second directory entry; its final record is 80h = 128 If there are exactly 2 directory entries per logical extent this is the first directory entry; its final record is 80h + 80h = 256, and this entry is full. If there are more than 2 entries per logical extent, this entry is not full; the next record would result in EXT = 2, RC = 1. If the file is written sequentially, then we know in #1 that the file has 80h +7fh=255 total records. If it is written randomly, all we know (without inspecting the group numbers) is that there is at least one record, the 255th; there may be others, including some in higher-numbered extents. In #2, assuming for example exactly 2 logical extents per directory entry, there may be a second directory entry that is totally empty (EXT=2, RC = 0). This can happen when a sequentially-written file is exactly 256 records long; the bdos internally closes the directory entry, creates a new one, and then is told by the program to close the file. Regarding (c) above, several OEM's and ramdisk suppliers (Televideo, SWP, ...) have defined disk formats that do not use all 8/16 group slots in a single directory entry. Apparently they weren't able to distinguish logical and physical extents! The result is unnecessary extra directory entries for large files and additional headaches for programmers. COPYING random files (ones containing holes) is not so straightforward, because the utility must determine how to handle a destination disk that has a different allocation group size. In the general case, although the data records can be copied, I don't believe a "perfect copy" is possible, because the destination copy may not retain the same information about unwritten records that existed in the original. (Information about unwritten records is mostly inferred from missing group numbers.) This could conceiveably lead to errors in a database program that relied on the "unwritten-data" error from the bdos. (Consider, for example, copying a random-record database from a 2K to a 4K group disk, and then copying it back to a 2K disk.) --bridger mitchell ------------------------------ Date: 13 Mar 88 18:01:57 GMT From: portal!cup.portal.com!dick_a_wotiz@uunet.uu.net Subject: CP/M disk Directories > 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 ------------------------------ Date: 13 Mar 88 22:18:21 GMT From: portal!cup.portal.com!Robert_A_Freed@uunet.uu.net Subject: CP/M disk Directories 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 ------------------------------ Date: 13 Mar 88 20:02:21 GMT From: portal!cup.portal.com!dgood@uunet.uu.net Subject: CP/M disk Directories > 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. There is some confusion here between about the concept of an extent. Originally, in cp/m 1.x (how's that for comp.archaeology) an extent was, by definition, 16k. This was because each dir entry showed the location of 16 groups x 1k per group. With cp/m 2.x came a more flexible arrangement. Groups can be up to 16k each. It also became possible to use either eight or sixteen bit directory addressing for each group; each directory entry still contains 16 bytes of group addresses, which may now address either eight or sixteen groups. Thus an extent (the amount of a file handled by a single directory entry) became variable. However, to maintain compatibility with the earlier versions of cp/m, the physical directory entries continue to consider an extent as 16k (ALWAYS). In other words, we now have a physical extent, which might contain as much as 128k (16k group x 8 groups/dir entry), but our directory extent byte shows logical extents, which are always 16k! In your example the logical extent is 16k, but the physical extent is 32k. > B0:WORK>save 511 test.fil s ; create a file in 2 extents > ; minus 1 record Note that you have saved 2 physical extents, but 4 logical extents. > 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 Yes, 2 physical, 4 logical extents > 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 The RC byte shows the number of records (max 80h) in the LAST logical extent for that directory entry. Here, we'll have two logical extents, ext 0 & ext 1, for the first dir entry. > ; Ok, now we look at the directory... > > B0:WORK> > > DU3 B0? s5 > Group = 00:04, Track = 2, Sector = 5, Physical Sector = 4 > > 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\]^_| ^ --extent #0-- ^ ^ --extent #1-- ^ Since we have filled logical ext #0 and are into logical ext #1, we know that we have 80h records in logical ext #0. The RC byte shows 80h records in logical ext #1, the last logical extent in the dir entry. Remember that the extent byte shows the LAST logical extent in that directory entry, and the RC byte shows the number of records in that last logical extent. > 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| ^ --extent #2-- ^ ^ --extent #3-- ^ Again, 80h records in (full) logical ext #2, 7Fh records in logical ext #3. Dave Goodman dgood@cup.portal.com ------------------------------ Date: Tuesday, 15 March 1988 10:05-MST From: Bridger Mitchell <bridger%rcc@RAND-UNIX.ARPA> Subject: CP/M dir. extents - correction In my posting yesterday: Date: Mon, 14 Mar 88 12:01:05 PST From: Bridger Mitchell <bridger%rcc@rand-unix.ARPA> Subject: CP/M directory extents I got my tongue (keyboard?) twisted in describing two examples. Here's the corrected excerpt, in "<<<...>>>" examples: (with S2 and EXT appropriately masked to remove internal bdos flag bits) #1 S2 = 0, EXT = 1, RC = 7fh If there is 1 <<<logical extent per directory entry>>>, then this is the second directory entry; its final record is 7f=127. If there are 2 or more <<<logical extents per directory entry>>> this is the first directory entry; its final record is 80h + 7fh = 255. #2 S2 = 0, EXT =1, RC = 80h If there is 1 <<<logical extent per directory entry>>>, then this is the second directory entry; its final record is 80h = 128 If there are exactly 2 <<<logical extents per directory entry>>> this is the first directory entry; its final record is 80h + 80h = 256, and this entry is full. If there are more than 2 <<<logical extents per directory entry>>> this entry is not full; the next record would result in EXT = 2, RC = 1. --bridger ------------------------------ Date: 14 Mar 88 21:58:51 GMT From: portal!cup.portal.com!David_Michael_McCord@uunet.uu.net Subject: SB180 help? The Sb180 electronics and software make it virtually impossible to read or write 48tpi disks in a 96tpi drive. However, an inexepensive solution is to add a 48tpi drive to the system, and then you can read and write 48tpi formats to your heart's content, including mushdos if you buy the UNIFORM product from Micromint. I have an SB180 configured with 2 96tpi drives as A: and B:, and a 48tpi drive as C:. Works great. ------------------------------