blob: af6b009494023bc953d936ff89ccfe5ad91f9307 [file] [log] [blame]
\ See license at end of file
purpose: BPB management
hex
d# 4096 constant /sector-max
: /sector ( -- n ) bps w@ ;
: /cluster ( -- n ) spc c@ /sector * ;
: bytes>clusters ( #bytes -- #clusters ) /cluster /mod swap if 1+ then ;
: uncache-device ( -- ) 0 bps w! ;
: bytes>cl-entries ( #bytes -- #cl-entries )
fat-type c@ case
fat12 of 2 * 3 / endof
fat16 of 2/ endof
fat32 of 2/ 2/ endof
endcase
;
0 instance value dir-buf
\ 3 sectors contains an integral number of FAT entries for either the
\ 12-bit or 16-bit or 32-bit FAT format, thus avoiding fragments of entries.
: init-fat-cache ( -- )
\ We really should verify that the sector size is the same as it
\ used to be, in case a different floppy was inserted.
fat-cache @ 0= if
3 dup sectors/fat-cache w! ( #cache-sectors )
/sector * ( cache-size )
dup alloc-mem fat-cache ! ( cache-size )
bytes>cl-entries cl#/fat-cache w!
/cluster alloc-mem to dir-buf
then
-1 fat-sector ! false fat-dirty w!
;
: ?free-fat-cache ( -- )
fat-cache @ if
dir-buf /cluster free-mem
fat-cache @ sectors/fat-cache w@ /sector * free-mem
0 fat-cache !
then
;
: (set-device) ( device# -- ) current-device ! ;
\ XXX There must be a better way to do this. Right now, we just zap
\ the BPB cache for both removable devices. This really ought to be
\ device interface procedure.
: media-changed? ( -- flag )
[ifdef] notdef
current-device @
3"floppy (set-device) uncache-device
5"floppy (set-device) uncache-device
(set-device)
true
[else]
false
[then]
;
: free-bpb ( -- )
bpb @ ?dup if /sector-max free-mem 0 bpb ! then
;
: ?read-error ( error? -- )
if ( )
free-bpb
"CaR ". ." BIOS Parameter Block"
abort
then ( )
;
: not-bpb? ( -- error? )
bp_bps lew@ ( bps )
dup dup 1- and 0= ( bps power-of-2? )
swap d# 256 d# 4096 between and ( bps-ok? )
bp_nfats c@ 1 2 between and 0= ( error? )
;
: find-bpb ( -- )
?init-device \ Call the device's init routine
/sector-max alloc-mem bpb !
0 1 bpb @ read-sectors ?read-error
not-bpb? if
free-bpb
true abort" Not an MS-DOS formatted drive"
then
;
: alloc-fssector ( -- )
fssector @ 0= if /sector-max alloc-mem fssector ! then
;
: free-fssector ( -- )
fssector @ ?dup if /sector-max free-mem 0 fsinfo ! 0 fssector ! then
;
: not-fsinfo? ( -- error? )
0 fsinfo !
fssector @ /sector bounds do
i lel@ fssignature lel@ = if
i fsinfo ! leave
then
4 +loop
fsinfo @ 0=
;
: read-fsinfo ( sector# -- )
false fsinfos-dirty c!
alloc-fssector
1 fssector @ read-sectors if
free-fssector
"CaR ". ." File system information sector"
abort
then
not-fsinfo? if free-fssector then
;
: write-fsinfo ( -- )
fsinfos w@ 0<> fsinfos-dirty c@ and if
false fsinfos-dirty c!
fsinfos w@ 1 fssector @ write-sectors
if "CaW ". ." File info sector" abort then
then
;
\ This BPB parser implements Microsoft's recommended method
\ for determining whether a filesystem is FAT-16 or FAT-32.
variable nsects
: bpb>device ( -- )
bp_media c@ media c!
bp_bps lew@ bps w!
bp_spc c@ spc c!
bp_spf lew@ ?dup 0= if bp_bspf lel@ then spf l!
bp_nsects lew@ ?dup 0= if bp_xnsects lel@ then nsects l!
bp_ndirs lew@ /dirent * /sector 1- + /sector / #dir-sectors w!
\ nsects is TotSec
\ #dir-sectors is RootDirSectors
\ Sector number where the FAT starts.
\ bp_nhid is the number of sectors before the BPB sector.
\ bp_res is the number of sectors from the BPT sector to the
\ first FAT sector.
\ If the underlying disk driver handles partition offsets,
\ we don't need to handle bp_nhid here.
bp_res lew@ ( bp_nhid lel@ + )
dup fat-sector0 w! ( #resv-sectors )
spf l@ bp_nfats c@ * + ( #early-sectors )
dup dir-sector0 w! ( #early-sectors )
#dir-sectors w@ + cl-sector0 l! ( )
\ cl-sector0 is FirstDataSector
nsects l@ #dir-sectors w@ - spc c@ / ( #clusters )
dup d# 65525 >= if ( #clusters )
drop fat32 fat-type c!
0 dir-sector0 w!
bp_rdirclus lel@ rdirclus l!
bp_fsinfos lew@ dup read-fsinfo fsinfos w!
else
d# 4085 >= if fat16 else fat12 then fat-type c!
0 fsinfo ! 0 fssector ! false fsinfos-dirty c!
0 fsinfos w! 0 rdirclus l!
then
\ The number of clusters is limited both by space for clusters numbers
\ in the FAT and by disk space for storage of the actual clusters.
\ It would be silly to waste disk space by making the FAT too small,
\ but I am paranoid so I check both limits.
\ Calculate the number of clusters the FAT can represent
spf l@ /sector * bytes>cl-entries ( #clusters )
\ Compare it with the number of clusters for which there is disk space
nsects l@
cl-sector0 l@ - spc c@ / 2 + min 1-
max-cl# l!
;
: ?read-bpb ( -- )
/sector 0= if \ Read bpb if necessary
init-sector-size
find-bpb
bp_bps lew@ bps w@ <> if
." WARNING: BPB sector size differs from device sector size" cr
then
bpb>device
init-fat-cache
\ Start with the root directory as the current working directory
rdirclus @ dv_cwd-cl l!
free-bpb
then
;
: set-device ( device# -- ) (set-device) ?read-bpb ;
\ : stand-init ( -- ) stand-init clear-device-records ;
\ LICENSE_BEGIN
\ Copyright (c) 2006 FirmWorks
\
\ Permission is hereby granted, free of charge, to any person obtaining
\ a copy of this software and associated documentation files (the
\ "Software"), to deal in the Software without restriction, including
\ without limitation the rights to use, copy, modify, merge, publish,
\ distribute, sublicense, and/or sell copies of the Software, and to
\ permit persons to whom the Software is furnished to do so, subject to
\ the following conditions:
\
\ The above copyright notice and this permission notice shall be
\ included in all copies or substantial portions of the Software.
\
\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\
\ LICENSE_END