Skip to content

Commit

Permalink
'Get cluster information' function call, and improvements to EMUFILE
Browse files Browse the repository at this point in the history
  • Loading branch information
Konamiman committed Oct 9, 2019
1 parent 644fcdc commit cf0cc8a
Show file tree
Hide file tree
Showing 16 changed files with 529 additions and 14 deletions.
91 changes: 91 additions & 0 deletions docs/Nextor 2.1 Programmers Reference.md
Expand Up @@ -52,6 +52,8 @@

[3.13. Enable or disable the Z80 access mode for a driver (_Z80MODE, 7Dh)](#313-enable-or-disable-the-z80-access-mode-for-a-driver-_z80mode-7dh)

[3.14. Get information for a cluster on a FAT drive (_GETCLUS, 7Eh)](#314-get-information-for-a-cluster-on-a-fat-drive-_getclus-7eh)

[4. New error codes](#4-new-error-codes)

[5. Extended mapper support routines](#5-extended-mapper-support-routines)
Expand Down Expand Up @@ -637,6 +639,91 @@ Note that the Z80 access mode is enabled or disabled for a whole driver, affecti

The Z80 access mode applies to MSX-DOS drivers only. Nextor will never change the CPU when accessing drive-based and device-based drivers.


### 3.14. Get information for a cluster on a FAT drive (_GETCLUS, 7Eh)

```
Parameters: C = 7EH (_GETCLUS)
A = Drive number (0=default, 1=A: etc.)
DE = Cluster number
HL = Pointer to a 16 byte buffer
Results: A = Error code
```

This function fills a user buffer with information related to a given cluster number for a given drive,
provided that the drive is mapped to a FAT12 or FAT16 filesystem. This function, in combination with
[RDDRV](#33-read-absolute-sectors-from-drive-_rddrv-73h) and [WRDRV](#34-write-absolute-sectors-to-drive-_wrdrv-74h),
can be useful for tools that perform low-level disk manipulation such as defragmenters.

The information returned in the buffer is as follows:

* +0: FAT sector number that contains the entry for the cluster (2 bytes)
* +2: Offset in the FAT sector where the entry for the cluster is located (0-511) (2 bytes)
* +4: First data sector number the cluster refers to (4 bytes)
* +8: Value of the FAT entry for the cluster (2 bytes)
* +10: Size of a cluster in sectors for the drive (1 byte)
* +11: Flags (1 byte)
* bit 0: set if the drive is FAT12
* bit 1: set if the drive is FAT16
* bit 2: set if the FAT entry for the cluster is an odd entry (FAT12 only)
* bit 3: set if the cluster is the last one of a file
* bit 4: set if the cluster is free
* bits 5-7: unused, always zero
* +12-+15: Unused, always zero

If the drive is neither FAT12 nor FAT16, this function will return a .NDOS error; this means that either
the FAT12 flag or the FAT16 flag will always be set if the function returns no error. Note however that this might not
be true in future versions of Nextor (in case that support for other FAT variants is added), therefore
you should always check both flags and not assume that one being clear means that the other one is set.

If the supplied cluster number doesn't exist in the specified drive, an .ICLUS error will be returned.
Note that 0 and 1 are always invalid cluster numbers (the bytes for these entries in the first FAT sector are unused).

The value of the FAT entry for the cluster has the usual meaning in a FAT filesystem:

* 0 means that the cluster is free
* 0FF8h-0FFFh for FAT 12 and FFF8h-FFFFh for FAT16 mean that the cluster is the last one of a file
* Other value is the number of the next cluster where the data for a file continues

For convenience, the "cluster is free" and "cluster is the last one of a file" flags are provided so that
the first two cases can be easily detected without checking the value of the FAT entry itself.

FAT entries for FAT12 can be even or odd, as indicated by the "entry is odd" flag. The value is stored differently in each case;
if "X" is the value of "offset in the FAT sector" and "peek(X)" is the byte value stored in X, then the value is:

* For even entries: `peek(X) + ((peek(X+1) and &HF) * 256)`
* For odd entries: `((peek(X) \ 16) and &HF) + (peek(X+1) * 16)`

For convenience here's a diagram showing an example of FAT12 even and odd entries, based on the one present at
[MSX2 Technical Handbook, chapter 3](https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Chapter3.md):

```
|4 bits |4 bits |
FAT -----------------
start address ->| F 0 | Media ID
|---------------|
+1 | F F | dummy entry
|---------------|
+2 | F F | dummy entry
|---------------|
+3 | 1 2 | Entry for cluster 2 : offset = 3, value = 412h (even entry)
|---------------|
+4 | 3 | 4 | Entry for cluster 3 : offset = 4, value = 563h (odd entry)
|---------------|
+5 | 5 6 |
|---------------|
+6 | 7 | 8 | Entry for cluster 4 : offset = 6, value = 978h (even entry)
|---------------|
+7 | | 9 |
---------
```

For FAT16 entries it's much simpler: these are stored in the byte at the specified offset and the next one in little endian, so `peek(X) + (256 * peek(X+1))`.

Note that if the offset in the FAT sector is 511, then the entry is split between the last byte in "FAT sector number that contains the entry" and the first byte of the next sector.
This can happen on FAT12 only.


## 4. New error codes

New error codes are defined to handle error conditions when managing the new features of Nextor. These errors are returned in MSX-DOS 1 mode as well by the new functions supported in this mode.
Expand Down Expand Up @@ -667,6 +754,10 @@ An attempt to open or alter a mounted file, or to perform any other disallowed o

Attempt to mount a file that is smaller than 512 bytes or larger than 32 MBytes.

* Invalid cluster number (.ICLUS, 0B0h)

The cluster number supplied to the [_GETCLUS](#314-get-information-for-a-cluster-on-a-fat-drive-_getclus-7eh) function doesn't exist in the drive.


## 5. Extended mapper support routines

Expand Down
6 changes: 3 additions & 3 deletions source/command/msxdos/compile.bat
@@ -1,9 +1,9 @@
@echo off
cls

copy ..\..\msxdos25\*.inc
copy ..\..\msxdos25\codes.mac
copy ..\..\msxdos25\data.mac
copy ..\..\kernel\*.inc
copy ..\..\kernel\codes.mac
copy ..\..\kernel\data.mac
for %%A in (CODES,DATA,KMSG,MESSAGES,REAL,REF,RELOC,VER,END) do cpm32 M80 =%%A
copy NOKMSG.MAC USEKMSG.MAC
cpm32 M80 =SYS
Expand Down
2 changes: 2 additions & 0 deletions source/command/msxdos/sys.mac
Expand Up @@ -853,6 +853,7 @@ BADNO EQU 32H ; Function no. used for un-implemented fns.
DEFW @MAPDRV ; Map a drive to a driver/device/LUN/sector

DEFW @Z80MODE ; Enable or disable the Z80 access mode for a driver
DEFW @GETCLUS ; Get information about a cluster in a FAT drive
;
MAXFN EQU ($-FNTAB)/2 ; Largest function number.
;
Expand Down Expand Up @@ -1391,6 +1392,7 @@ KBDOS:

@GDRVR:
@GDLI:
@GETCLUS:
push hl
LD HL,BUFF3
call GO_BDOS##
Expand Down
4 changes: 2 additions & 2 deletions source/command/msxdos/ver.mac
Expand Up @@ -9,8 +9,8 @@
;
;
VERSION EQU 2
RELEASE EQU 1*256+0 ; Version 2.10.
CRYEAR EQU 2014
RELEASE EQU 1*256+1 ; Version 2.11.
CRYEAR EQU 2019
;
GLOBAL VERSION, RELEASE, CRYEAR
;
Expand Down
2 changes: 2 additions & 0 deletions source/kernel/bank0/bdos.mac
Expand Up @@ -411,6 +411,7 @@ FUNTAB: DEFW @TERM0 ;Terminate program with no error.
DEFW @MAPDRV ; Map a drive letter to a drive or device/LUN/partition

DEFW @Z80MODE ; Enable or disable the Z80 access mode for a driver
DEFW @GETCLUS ; Get information about a cluster in a FAT drive
;
MAXFN EQU ($-FUNTAB)/2 ;Largest function number.
;
Expand Down Expand Up @@ -908,6 +909,7 @@ STRCPY: LD A,(HL) ;Get character from string.
;
@GDRVR:
@GDLI:
@GETCLUS:
push hl
LD HL,(BUF_3##)
call GO_BDOS##
Expand Down
9 changes: 6 additions & 3 deletions source/kernel/bank1/msg.mac
Expand Up @@ -237,8 +237,9 @@ ERR_MSG_TABLE:
err .IDEVL, <"Invalid device or logical unit">
err .IPART, <"Invalid partition number">
err .PUSED, <"Partition is already in use">
err .FMNT, <"File is mounted">
err .BFSZ, <"Bad file size">
err .FMNT, <"File is mounted">
err .BFSZ, <"Bad file size">
err .ICLUS, <"Invalid cluster number">
;
;
; The following are errors which the KBDOS may pass to the ABORT routine.
Expand Down Expand Up @@ -436,7 +437,9 @@ ERR_KMSG_TABLE:
err .IDEVL, <"�����ȃf�o�C�X�܂��͘_�����j�b�g�ł�"> ;<"Invalid device or logical unit">
err .IPART, <"�����ȃp�[�e�B�V�����ԍ�"> ;<"Invalid partition number">
err .PUSED, <"�p�[�e�B�V�������g�p���ł�"> ;<"Partition is already in use">

err .FMNT, <"�t�@�C�����}�E���g����Ă��܂�"> ;<"File is mounted">
err .BFSZ, <"�����ȃt�@�C���T�C�Y"> ;<"Bad file size">
err .ICLUS, <"�����ȃN���X�^�[�ԍ�"> ;<"Invalid cluster number">
;
;
; The following are errors which the KBDOS may pass to the ABORT routine.
Expand Down
19 changes: 17 additions & 2 deletions source/kernel/bank2/fat.mac
Expand Up @@ -50,6 +50,15 @@ retry_fat_err:
jr z,retry_fat_err ;No point retrying.
jr return_0ffffh ;Ignore - return 0FFFFh
;

;Convert pointer to FAT entry returned by FIND_FAT_ENTRY
;into the value of the FAT entry.
;Input: HL = address of unit descriptor
; DE and F from FIND_FAT_ENTRY
;Output: DE = Value of FAT entry
; Cy = 1 if it's the last cluster of the file

PROC RDFATENTRY
no_fat_error: push hl
ld a,(de)
ld l,a ;A:L := 2 bytes from the FAT
Expand Down Expand Up @@ -78,7 +87,10 @@ lookup_fat16: ld h,a ; is zero.
sbc hl,de ; value to 0FFFFh.
pop hl
ret nc
return_0ffffh: ld de,0FFFFh

ld (TEMP_FAT##+4),de ; Save real cluster number for F_GETCLUS
return_0ffffh:
ld de,0FFFFh
ret
;
;
Expand Down Expand Up @@ -287,6 +299,7 @@ pop_de_ret:
;
;------------------------------------------------------------------------------
;
PROC FNDFAT
FIND_FAT_ENTRY:
;
; This routine is given a FAT entry number which it checks for validity,
Expand Down Expand Up @@ -345,7 +358,8 @@ endif
srl h
rr l
find_fat16: push af ;Save odd/even flag (carry)
push hl ;Save byte number
push hl ;Save byte number
ld (TEMP_FAT##+2),hl ;Save also for F_GETCLUS
;
;===== start mod FAT16 (support BUF_1 patch)
ld e,h ;DE := byte/512 = relative
Expand All @@ -359,6 +373,7 @@ find_fat16: push af ;Save odd/even flag (carry)
ld l,(ix+UD_RES##)
ld h,(ix+UD_RES##+1) ;Add on reserved sectors to get
add hl,de ; sector number required.
ld (TEMP_FAT##),hl ; Save FAT sector number, needed by F_GETCLUS
ex de,hl
pcall BF_FAT_SECTOR ;Get FAT sector into buffer.
;
Expand Down
1 change: 1 addition & 0 deletions source/kernel/bank2/kinit.mac
Expand Up @@ -808,6 +808,7 @@ kbdos_table:
dw F_MAPDRV## ;Map a drive letter to a drive or device/LUN/partition

dw F_Z80MODE## ;Enable or disable the Z80 access mode for a driver
dw F_GETCLUS## ;Get information about a cluster in a FAT drive
;
;
num_kbdos_fns equ ($-kbdos_table)/2
Expand Down
1 change: 1 addition & 0 deletions source/kernel/bank4/jump.mac
Expand Up @@ -81,6 +81,7 @@ jentry macro name

jentry DRVS2
jentry AUTO_ASPART
jentry F_GETCLUS

finish <JUMP>
end
128 changes: 128 additions & 0 deletions source/kernel/bank4/misc.mac
Expand Up @@ -360,7 +360,135 @@ dspace_c2k_loop:
dspace_end:
xor a
ret

;
;------------------------------------------------------------------------------
;
PROC F_GETCLUS

; Get information about a cluster on a FAT drive.
;
; Entry: C (A) = drive number (0=default)
; DE = cluster number
; HL = address of a 16 byte buffer to get information
; Returns: A = error code
; Information in (HL) as follows:
; +0 (2): Absolute FAT sector number that contains the entry for the cluster
; +2 (2): Offset in the FAT sector for the entry for the cluster (0-511)
; +4 (4): Absolute sector number in the device the cluster refers to
; +8 (2): Value of the FAT entry:
; 0: Unused cluster
; 0FF7h-0FFFh (FAT12) or FFF7h-FFFFh (FAT16): last cluster of the file
; Other: next cluster of the file
; +10 (1): Sectors per cluster of the drive
; +11 (1): Flags
; bit 0: set if the drive is FAT12
; bit 1: set if the drive is FAT16
; bit 2: set if it's an odd entry (always 0 on FAT16)
; bit 3: set if it's the last cluster of a file
; bit 4: set if it's an unused cluster
; +12..+15: Unused, always zero
;
push hl
push de
;ld c,a ;Validate the specified
ld b,0 ; drive and return if
ld ix,FIB_1## ; any error detected.
pcall VAL_FIB
or a
pop de
pop ix ;IX=user buffer
ret nz

;Set the drive parameters in the result

push ix
push hl ;Unit descriptor
pop ix

ld b,(ix+UD_CMSK##)
inc b ;Sectors per cluster
ld a,(ix+UD_FLAGS##)

push ix
pop hl
pop ix

and 11b ;FAT12/16 flags
ld (ix+11),a
or a
ld a,.NDOS##
ret z ;Drive is neither FAT12 nor FAT16
ld (ix+10),b

;Cluster numbers 0 and 1 are invalid

dec de
dec de
xor a
bit 7,d
ld a,.ICLUS##
ret nz
inc de
inc de

;Get cluster info

push de

push ix
pcall FNDFAT
pop ix
jr nz,FGC_BADCLUS

jr nc,FGC_ISEVEN
set 2,(ix+11) ;It's an odd entry
FGC_ISEVEN:

pcall RDFATENTRY
jr nc,FGC_NOLAST
set 3,(ix+11)
ld de,(TEMP_FAT##+4)
FGC_NOLAST:
ld (ix+8),e ;FAT entry value
ld (ix+9),d

ld a,d
or e
jr nz,FGC_ISUSED
set 4,(ix+11)
FGC_ISUSED:

pop de

xor a
pcall CLU_TO_SEC
ld (ix+4),e ;First absolute data sector number
ld (ix+5),d
ld (ix+6),a
ld (ix+7),0

ld hl,(TEMP_FAT##) ;FAT sector number
ld (ix),l
ld (ix+1),h
ld hl,(TEMP_FAT##+2) ;Offset of cluster entry in FAT
ld a,h
and 1 ;Convert to offset relative to the FAT sector
ld (ix+2),l
ld (ix+3),a

xor a
ld (ix+12),a
ld (ix+13),a
ld (ix+14),a
ld (ix+15),a
ret

FGC_BADCLUS:
pop de
ld a,.ICLUS##
ret

finish <MISC>
end
;

0 comments on commit cf0cc8a

Please sign in to comment.