mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 18:08:06 +11:00
New part: fs
Very incomplete, but if you play your cards right, you can, with the shell: 1. Create a new CFS 2. Mount it 3. Allocate a file with an arbitrary name 4. Have it listed with `fls`
This commit is contained in:
parent
07fde3cab5
commit
c0dbee78de
@ -16,6 +16,12 @@
|
|||||||
BLOCKDEV_ERR_OUT_OF_BOUNDS .equ 0x03
|
BLOCKDEV_ERR_OUT_OF_BOUNDS .equ 0x03
|
||||||
BLOCKDEV_ERR_UNSUPPORTED .equ 0x04
|
BLOCKDEV_ERR_UNSUPPORTED .equ 0x04
|
||||||
|
|
||||||
|
BLOCKDEV_SEEK_ABSOLUTE .equ 0
|
||||||
|
BLOCKDEV_SEEK_FORWARD .equ 1
|
||||||
|
BLOCKDEV_SEEK_BACKWARD .equ 2
|
||||||
|
BLOCKDEV_SEEK_BEGINNING .equ 3
|
||||||
|
BLOCKDEV_SEEK_END .equ 4
|
||||||
|
|
||||||
; *** VARIABLES ***
|
; *** VARIABLES ***
|
||||||
; Pointer to the selected block device. A block device is a 8 bytes block of
|
; Pointer to the selected block device. A block device is a 8 bytes block of
|
||||||
; memory with pointers to GetC, PutC, Seek and Tell routines, in that order.
|
; memory with pointers to GetC, PutC, Seek and Tell routines, in that order.
|
||||||
@ -133,13 +139,13 @@ blkPutC:
|
|||||||
; Set position of selected device to the value specified in HL
|
; Set position of selected device to the value specified in HL
|
||||||
blkSeek:
|
blkSeek:
|
||||||
push de
|
push de
|
||||||
cp 1
|
cp BLOCKDEV_SEEK_FORWARD
|
||||||
jr z, .forward
|
jr z, .forward
|
||||||
cp 2
|
cp BLOCKDEV_SEEK_BACKWARD
|
||||||
jr z, .backward
|
jr z, .backward
|
||||||
cp 3
|
cp BLOCKDEV_SEEK_BEGINNING
|
||||||
jr z, .beginning
|
jr z, .beginning
|
||||||
cp 4
|
cp BLOCKDEV_SEEK_END
|
||||||
jr z, .end
|
jr z, .end
|
||||||
; all other modes are considered absolute
|
; all other modes are considered absolute
|
||||||
jr .seek ; for absolute mode, HL is already correct
|
jr .seek ; for absolute mode, HL is already correct
|
||||||
|
@ -70,15 +70,20 @@ unsetZ:
|
|||||||
|
|
||||||
; *** STRINGS ***
|
; *** STRINGS ***
|
||||||
|
|
||||||
; Increase HL until the memory address it points to is null for a maximum of
|
; Increase HL until the memory address it points to is equal to A for a maximum
|
||||||
; 0xff bytes. Returns the new HL value as well as the number of bytes iterated
|
; of 0xff bytes. Returns the new HL value as well as the number of bytes
|
||||||
; in A.
|
; iterated in A.
|
||||||
findnull:
|
; If a null char is encountered before we find A, processing is stopped in the
|
||||||
|
; same way as if we found our char (so, we look for A *or* 0)
|
||||||
|
findchar:
|
||||||
push bc
|
push bc
|
||||||
|
ld c, a ; let's use C as our cp target
|
||||||
ld a, 0xff
|
ld a, 0xff
|
||||||
ld b, a
|
ld b, a
|
||||||
|
|
||||||
.loop: ld a, (hl)
|
.loop: ld a, (hl)
|
||||||
|
cp c
|
||||||
|
jr z, .end
|
||||||
cp 0
|
cp 0
|
||||||
jr z, .end
|
jr z, .end
|
||||||
inc hl
|
inc hl
|
||||||
|
294
parts/fs.asm
Normal file
294
parts/fs.asm
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
; fs
|
||||||
|
;
|
||||||
|
; Collapse OS filesystem (CFS) is not made to be convenient, but to be simple.
|
||||||
|
; This is little more than "named storage blocks". Characteristics:
|
||||||
|
;
|
||||||
|
; * a filesystem sits upon a blockdev. It needs GetC, PutC, Seek.
|
||||||
|
; * No directory. Use filename prefix to group.
|
||||||
|
; * First block of each file has metadata. Others are raw data.
|
||||||
|
; * No FAT. Files are a chain of blocks of a predefined size. To enumerate
|
||||||
|
; files, you go through metadata blocks.
|
||||||
|
; * Fixed allocation. File size is determined at allocation time and cannot be
|
||||||
|
; grown, only shrunk.
|
||||||
|
; * New allocations try to find spots to fit in, but go at the end if no spot is
|
||||||
|
; large enough.
|
||||||
|
; * Block size is 0x100, max block count per file is 8bit, that means that max
|
||||||
|
; file size: 64k - metadata overhead.
|
||||||
|
;
|
||||||
|
; *** Selecting a "source" blockdev
|
||||||
|
;
|
||||||
|
; This unit exposes "fson" shell command to "mount" CFS upon the currently
|
||||||
|
; selected device, at the point where its seekptr currently sits. This checks
|
||||||
|
; if we have a valid first block and spits an error otherwise.
|
||||||
|
;
|
||||||
|
; "fson" takes an optional argument which is a number. If non-zero, we don't
|
||||||
|
; error out if there's no metadata: we create a new CFS fs with an empty block.
|
||||||
|
;
|
||||||
|
; The can only be one "mounted" fs at once. Selecting another blockdev through
|
||||||
|
; "bsel" foesn't affect the currently mounted fs, which can still be interacted
|
||||||
|
; with (which is important if we want to move data around).
|
||||||
|
;
|
||||||
|
; *** Block metadata
|
||||||
|
;
|
||||||
|
; At the beginning of the first block of each file, there is this data
|
||||||
|
; structure:
|
||||||
|
;
|
||||||
|
; 3b: Magic number "CFS"
|
||||||
|
; 1b: Allocated block count, including the first one. Except for the "ending"
|
||||||
|
; block, this is never zero.
|
||||||
|
; 2b: Size of file in bytes (actually written). Little endian.
|
||||||
|
; 26b: file name, null terminated. last byte must be null.
|
||||||
|
;
|
||||||
|
; That gives us 32 bytes of metadata for first first block, leaving a maximum
|
||||||
|
; file size of 0xffe0.
|
||||||
|
;
|
||||||
|
; *** Last block of the chain
|
||||||
|
;
|
||||||
|
; The last block of the chain is either a block that has no valid block next to
|
||||||
|
; it or a block that reports a 0 allocated block count.
|
||||||
|
;
|
||||||
|
; *** Deleted files
|
||||||
|
;
|
||||||
|
; When a file is deleted, its name is set to null. This indicates that the
|
||||||
|
; allocated space is up for grabs.
|
||||||
|
;
|
||||||
|
; *** File "handles"
|
||||||
|
;
|
||||||
|
; Programs will not typically open files themselves. How it works with CFS is
|
||||||
|
; that it exposes an API to plug target files in a blockdev ID. This all
|
||||||
|
; depends on how you glue parts together, but ideally, you'll have two
|
||||||
|
; fs-related blockdev IDs: one for reading, one for writing.
|
||||||
|
;
|
||||||
|
; Being plugged into the blockdev system, programs will access the files as they
|
||||||
|
; would with any other block device.
|
||||||
|
;
|
||||||
|
; *** Creating a new FS
|
||||||
|
;
|
||||||
|
; A valid Collapse OS filesystem is nothing more than the 3 bytes 'C', 'F', 'S'
|
||||||
|
; next to each other. Placing them at the right place is all you have to do to
|
||||||
|
; create your FS.
|
||||||
|
|
||||||
|
; *** DEFINES ***
|
||||||
|
; Number of handles we want to support
|
||||||
|
; FS_HANDLE_COUNT
|
||||||
|
; *** CONSTS ***
|
||||||
|
FS_MAX_NAME_SIZE .equ 0x1a
|
||||||
|
; Size in bytes of a FS handle:
|
||||||
|
; * 2 bytes for starting offset
|
||||||
|
; * 2 bytes for file size (we could fetch it from metadata all the time, but it
|
||||||
|
; could be time consuming depending on the underlying device).
|
||||||
|
; * 2 bytes for current position.
|
||||||
|
; Starting offset is the *metadata* offset. We need, when we write to a handle,
|
||||||
|
; to change the size of the file.
|
||||||
|
FS_HANDLE_SIZE .equ 6
|
||||||
|
FS_ERR_NO_FS .equ 0x5
|
||||||
|
|
||||||
|
; *** VARIABLES ***
|
||||||
|
; A copy of BLOCKDEV_SEL when the FS was mounted. 0 if no FS is mounted.
|
||||||
|
FS_BLKSEL .equ FS_RAMSTART
|
||||||
|
; Offset at which our FS start on mounted device
|
||||||
|
FS_START .equ FS_BLKSEL+2
|
||||||
|
; Offset at which we are currently pointing to with regards to our routines
|
||||||
|
; below, which all assume this offset as a context. This offset is not relative
|
||||||
|
; to FS_START. It can be used directly with blkSeek.
|
||||||
|
FS_PTR .equ FS_START+2
|
||||||
|
; A place to store tmp data
|
||||||
|
FS_TMP .equ FS_PTR+2
|
||||||
|
FS_HANDLES .equ FS_TMP+0x20
|
||||||
|
FS_RAMEND .equ FS_HANDLES+(FS_HANDLE_COUNT*FS_HANDLE_SIZE)
|
||||||
|
|
||||||
|
; *** CODE ***
|
||||||
|
|
||||||
|
; *** Navigation ***
|
||||||
|
|
||||||
|
; Resets FS_PTR to the beginning. Errors out if no FS is mounted.
|
||||||
|
; Sets Z if success, unset if error
|
||||||
|
fsBegin:
|
||||||
|
push hl
|
||||||
|
ld hl, (FS_START)
|
||||||
|
ld (FS_PTR), hl
|
||||||
|
pop hl
|
||||||
|
call fsPlace
|
||||||
|
call fsIsValid ; sets Z
|
||||||
|
call fsPlace
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Change current position to the next block with metadata. If it can't (if this
|
||||||
|
; is the last valid block), doesn't move.
|
||||||
|
; Sets Z according to whether we moved.
|
||||||
|
fsNext:
|
||||||
|
call unsetZ
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Make sure that our underlying blockdev is correcly placed.
|
||||||
|
; All other routines assumer a properly placed blkdev cursor.
|
||||||
|
fsPlace:
|
||||||
|
push af
|
||||||
|
push hl
|
||||||
|
xor a
|
||||||
|
ld hl, (FS_PTR)
|
||||||
|
call blkSeek
|
||||||
|
pop hl
|
||||||
|
pop af
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Create a new file with A blocks allocated to it.
|
||||||
|
; Before doing so, enumerate all blocks in search of a deleted file with
|
||||||
|
; allocated space big enough. If it does, it will either take the whole space
|
||||||
|
; if the allocated space asked is exactly the same, or of it isn't, split the
|
||||||
|
; free space in 2 and create a new deleted metadata block next to the newly
|
||||||
|
; created block.
|
||||||
|
; Places FS_PTR to the newly allocated block. You have to write the new
|
||||||
|
; filename yourself.
|
||||||
|
fsAlloc:
|
||||||
|
push hl
|
||||||
|
push af ; keep A for later
|
||||||
|
call fsPlace
|
||||||
|
ld a, BLOCKDEV_SEEK_FORWARD
|
||||||
|
ld hl, 3
|
||||||
|
call blkSeek
|
||||||
|
pop af ; now we want our A arg
|
||||||
|
call blkPutC
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
; *** Metadata ***
|
||||||
|
|
||||||
|
; Sets Z according to whether the current block is valid.
|
||||||
|
; Don't call other FS routines without checking block validity first: other
|
||||||
|
; routines don't do checks.
|
||||||
|
fsIsValid:
|
||||||
|
push hl
|
||||||
|
ld b, 0x3
|
||||||
|
ld hl, FS_TMP
|
||||||
|
call blkRead
|
||||||
|
jr nz, .error
|
||||||
|
ld a, 3
|
||||||
|
ld de, .magic
|
||||||
|
call strncmp
|
||||||
|
jr nz, .error
|
||||||
|
; success
|
||||||
|
jr .end ; Z is set at this point
|
||||||
|
.error:
|
||||||
|
call unsetZ
|
||||||
|
.end:
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
.magic:
|
||||||
|
.db "CFS"
|
||||||
|
|
||||||
|
; Return, in A, the number of allocated blocks at current position.
|
||||||
|
fsAllocatedBlocks:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Return, in HL, the file size at current position.
|
||||||
|
fsFileSize:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Return HL, which points to a null-terminated string which contains the
|
||||||
|
; filename at current position.
|
||||||
|
fsFileName:
|
||||||
|
push af
|
||||||
|
ld a, BLOCKDEV_SEEK_FORWARD
|
||||||
|
ld hl, 6
|
||||||
|
call blkSeek
|
||||||
|
ld b, FS_MAX_NAME_SIZE
|
||||||
|
ld hl, FS_TMP
|
||||||
|
call blkRead
|
||||||
|
pop af
|
||||||
|
ret
|
||||||
|
|
||||||
|
; *** Handling ***
|
||||||
|
|
||||||
|
; Open file at current position into handle at (HL)
|
||||||
|
fsOpen:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Ensures that file size in metadata corresponds to file size in handle as (HL).
|
||||||
|
fsCommit:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Read a byte in handle at (HL), put it into A and advance the handle's
|
||||||
|
; position.
|
||||||
|
; Z is set on success, unset if handle is at the end of the file.
|
||||||
|
fsRead:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Write byte A in handle at (HL) and advance the handle's position.
|
||||||
|
; Z is set on success, unset if handle is at the end of the allocated space.
|
||||||
|
fsWrite:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Sets position of handle (HL) to DE. This position does *not* include metadata.
|
||||||
|
; It is an offset that starts at actual data.
|
||||||
|
; Sets Z if offset is within bounds, unsets Z if it isn't.
|
||||||
|
fsSeek:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; *** SHELL COMMANDS ***
|
||||||
|
; Mount the fs subsystem upon the currently selected blockdev at current offset.
|
||||||
|
; Verify is block is valid and error out if its not, mounting nothing.
|
||||||
|
; Upon mounting, copy currently selected device in FS_BLKSEL.
|
||||||
|
fsOnCmd:
|
||||||
|
.db "fson", 0, 0, 0
|
||||||
|
push hl
|
||||||
|
call blkTell
|
||||||
|
ld (FS_PTR), hl
|
||||||
|
call fsPlace
|
||||||
|
call fsIsValid
|
||||||
|
jr nz, .error
|
||||||
|
; success
|
||||||
|
ld (FS_START), hl
|
||||||
|
xor a
|
||||||
|
jr .end
|
||||||
|
.error:
|
||||||
|
ld a, FS_ERR_NO_FS
|
||||||
|
.end:
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Lists filenames in currently active FS
|
||||||
|
flsCmd:
|
||||||
|
.db "fls", 0, 0, 0, 0
|
||||||
|
call fsBegin
|
||||||
|
jr nz, .error
|
||||||
|
call fsFileName
|
||||||
|
call printstr
|
||||||
|
call printcrlf
|
||||||
|
xor a
|
||||||
|
jr .end
|
||||||
|
.error:
|
||||||
|
ld a, FS_ERR_NO_FS
|
||||||
|
.end:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; Takes one byte block number to allocate as well we one string arg filename
|
||||||
|
; and allocates a new file in the current fs.
|
||||||
|
fnewCmd:
|
||||||
|
.db "fnew", 0b001, 0b1001, 0b001
|
||||||
|
push hl
|
||||||
|
push de
|
||||||
|
ld a, (hl)
|
||||||
|
ex de, hl
|
||||||
|
inc de
|
||||||
|
call intoDE
|
||||||
|
ex de, hl
|
||||||
|
push hl ; save the filename for later
|
||||||
|
call fsAlloc
|
||||||
|
call fsPlace
|
||||||
|
ld a, BLOCKDEV_SEEK_FORWARD
|
||||||
|
ld hl, 6
|
||||||
|
call blkSeek
|
||||||
|
pop hl ; now we need the filename
|
||||||
|
.loop:
|
||||||
|
ld a, (hl)
|
||||||
|
cp 0
|
||||||
|
jr z, .end
|
||||||
|
call blkPutC
|
||||||
|
inc hl
|
||||||
|
jr .loop
|
||||||
|
.end:
|
||||||
|
pop de
|
||||||
|
pop hl
|
||||||
|
xor a
|
||||||
|
ret
|
@ -91,7 +91,8 @@ shellLoop:
|
|||||||
; save char for later
|
; save char for later
|
||||||
ex af, af'
|
ex af, af'
|
||||||
ld hl, SHELL_BUF
|
ld hl, SHELL_BUF
|
||||||
call findnull ; HL points to where we need to write
|
xor a ; look for null
|
||||||
|
call findchar ; HL points to where we need to write
|
||||||
; A is the number of chars in the buf
|
; A is the number of chars in the buf
|
||||||
cp SHELL_BUFSIZE
|
cp SHELL_BUFSIZE
|
||||||
jr z, .do ; A == bufsize? then our buffer is full. do!
|
jr z, .do ; A == bufsize? then our buffer is full. do!
|
||||||
@ -157,8 +158,8 @@ shellParse:
|
|||||||
call intoDE ; Jump from the table entry to the cmd addr.
|
call intoDE ; Jump from the table entry to the cmd addr.
|
||||||
|
|
||||||
; advance the HL pointer to the beginning of the args.
|
; advance the HL pointer to the beginning of the args.
|
||||||
ld a, 4
|
ld a, ' '
|
||||||
call addHL
|
call findchar
|
||||||
|
|
||||||
; Now, let's have DE point to the argspecs
|
; Now, let's have DE point to the argspecs
|
||||||
ld a, 4
|
ld a, 4
|
||||||
|
Loading…
Reference in New Issue
Block a user