diff options
Diffstat (limited to 'roms/SLOF/slof/fs/packages/ext2-files.fs')
-rw-r--r-- | roms/SLOF/slof/fs/packages/ext2-files.fs | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/roms/SLOF/slof/fs/packages/ext2-files.fs b/roms/SLOF/slof/fs/packages/ext2-files.fs new file mode 100644 index 000000000..716913714 --- /dev/null +++ b/roms/SLOF/slof/fs/packages/ext2-files.fs @@ -0,0 +1,281 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +s" ext2-files" device-name + +INSTANCE VARIABLE first-block +INSTANCE VARIABLE inode-size +INSTANCE VARIABLE block-size +INSTANCE VARIABLE inodes/group + +INSTANCE VARIABLE blocks-per-group +INSTANCE VARIABLE group-descriptors +INSTANCE VARIABLE desc-size + +: seek s" seek" $call-parent ; +: read s" read" $call-parent ; + +INSTANCE VARIABLE data +INSTANCE VARIABLE #data +INSTANCE VARIABLE indirect-block +INSTANCE VARIABLE dindirect-block + +: free-data + data @ ?dup IF #data @ free-mem 0 data ! THEN ; +: read-data ( offset size -- ) + free-data dup #data ! alloc-mem data ! + xlsplit seek -2 and ABORT" ext2-files read-data: seek failed" + data @ #data @ read #data @ <> ABORT" ext2-files read-data: read failed" ; + +: read-block ( block# -- ) + block-size @ * block-size @ read-data ; + +INSTANCE VARIABLE inode +INSTANCE VARIABLE file-len +INSTANCE VARIABLE blocks \ data from disk blocks +INSTANCE VARIABLE #blocks +INSTANCE VARIABLE ^blocks \ current pointer in blocks +INSTANCE VARIABLE #blocks-left +: blocks-read ( n -- ) dup negate #blocks-left +! 4 * ^blocks +! ; +: read-indirect-blocks ( indirect-block# -- ) + read-block data @ data off + dup #blocks-left @ 4 * block-size @ min dup >r ^blocks @ swap move + r> 2 rshift blocks-read block-size @ free-mem ; + +: read-double-indirect-blocks ( double-indirect-block# -- ) + \ Resolve one level of indirection and call read-indirect-block + read-block data @ indirect-block ! data off + BEGIN + indirect-block @ l@-le dup 0 <> + WHILE + read-indirect-blocks + 4 indirect-block +! \ point to next indirect block + REPEAT + drop \ drop 0, the invalid block number +; + +: read-triple-indirect-blocks ( triple-indirect-block# -- ) + \ Resolve one level of indirection and call double-indirect-block + read-block data @ dindirect-block ! data off + BEGIN + dindirect-block @ l@-le dup 0 <> + WHILE + read-double-indirect-blocks + 4 dindirect-block +! \ point to next double indirect block + REPEAT + drop \ drop 0, the invalid block number +; + +: inode-i-block ( inode -- block ) 28 + ; +80000 CONSTANT EXT4_EXTENTS_FL +: inode-i-flags ( inode -- i_flags ) 20 + l@-le ; +F30A CONSTANT EXT4_EH_MAGIC +: extent-tree-entries ( iblock -- entries ) C + ; + +STRUCT + 2 field ext4-eh>magic + 2 field ext4-eh>entries + 2 field ext4-eh>max + 2 field ext4-eh>depth + 4 field ext4-eh>generation +CONSTANT /ext4-eh + +STRUCT + 4 field ext4-ee>block + 2 field ext4-ee>len + 2 field ext4-ee>start_hi + 4 field ext4-ee>start_lo +CONSTANT /ext4-ee + +: ext4-ee-start ( entries -- ee-start ) + dup ext4-ee>start_hi w@-le 32 lshift + swap + ext4-ee>start_lo l@-le or +; + +: expand-blocks ( start len -- ) + bounds + ?DO + i ^blocks @ l!-le + 1 blocks-read + 1 +LOOP +; + +\ [0x28..0x34] ext4_extent_header +\ [0x34..0x64] ext4_extent_idx[eh_entries if eh_depth > 0] (not supported) +\ ext4_extent[eh_entries if eh_depth == 0] +: read-extent-tree ( inode -- ) + inode-i-block + dup ext4-eh>magic w@-le EXT4_EH_MAGIC <> IF ." BAD extent tree magic" cr EXIT THEN + dup ext4-eh>depth w@-le 0 <> IF ." Root inode is not lead, not supported" cr EXIT THEN + \ depth=0 means it is a leaf and entries are ext4_extent[eh_entries] + dup ext4-eh>entries w@-le + >r + /ext4-eh + + r> + 0 + DO + dup ext4-ee-start + over ext4-ee>len w@-le ( ext4_extent^ start len ) + expand-blocks + /ext4-ee + + LOOP + drop +; + +\ Reads block numbers into blocks +: read-block#s ( -- ) + blocks @ ?dup IF #blocks @ 4 * free-mem THEN \ free blocks if allocated + inode @ 4 + l@-le file-len ! \ *file-len = i_size_lo + file-len @ block-size @ // #blocks ! \ *#blocks = roundup(file-len/block-size) + #blocks @ 4 * alloc-mem blocks ! \ *blocks = allocmem(*#blocks) + blocks @ ^blocks ! #blocks @ #blocks-left ! + inode @ inode-i-flags EXT4_EXTENTS_FL and IF inode @ read-extent-tree EXIT THEN + #blocks-left @ c min \ # direct blocks + inode @ inode-i-block over 4 * ^blocks @ swap move blocks-read + #blocks-left @ IF inode @ 58 + l@-le read-indirect-blocks THEN + #blocks-left @ IF inode @ 5c + l@-le read-double-indirect-blocks THEN + #blocks-left @ IF inode @ 60 + l@-le read-triple-indirect-blocks THEN +; + +: read-inode-table ( groupdesc -- table ) + dup 8 + l@-le \ reads bg_inode_table_lo + desc-size @ 20 > IF + over 28 + l@-le \ reads bg_inode_table_hi + 20 lshift or + THEN + nip +; + +: read-inode ( inode# -- ) + 1- inodes/group @ u/mod + desc-size @ * group-descriptors @ + + read-inode-table + block-size @ * \ # in group, inode table + swap inode-size @ * + xlsplit seek drop inode @ inode-size @ read drop +; + +: .rwx ( bits last-char-if-special special? -- ) + rot dup 4 and IF ." r" ELSE ." -" THEN + dup 2 and IF ." w" ELSE ." -" THEN + swap IF 1 and 0= IF upc THEN emit ELSE + 1 and IF ." x" ELSE ." -" THEN drop THEN ; +CREATE mode-chars 10 allot s" ?pc?d?b?-?l?s???" mode-chars swap move +: .mode ( mode -- ) + dup c rshift f and mode-chars + c@ emit + dup 6 rshift 7 and over 800 and 73 swap .rwx + dup 3 rshift 7 and over 400 and 73 swap .rwx + dup 7 and swap 200 and 74 swap .rwx ; +: .inode ( -- ) + base @ >r decimal + inode @ w@-le .mode \ file mode + inode @ 1a + w@-le 5 .r \ link count + inode @ 02 + w@-le 9 .r \ uid + inode @ 18 + w@-le 9 .r \ gid + inode @ 04 + l@-le 9 .r \ size + r> base ! ; + +80 CONSTANT EXT4_INCOMPAT_64BIT +: super-feature-incompat ( data -- flags ) 60 + l@-le ; +: super-desc-size ( data -- size ) FE + w@-le ; +: super-feature-incompat-64bit ( data -- true|false ) + super-feature-incompat EXT4_INCOMPAT_64BIT and 0<> +; + +: do-super ( -- ) + 400 400 read-data + data @ 14 + l@-le first-block ! + 400 data @ 18 + l@-le lshift block-size ! + data @ 28 + l@-le inodes/group ! + \ Check revision level... in revision 0, the inode size is always 128 + data @ 4c + l@-le 0= IF + 80 inode-size ! + ELSE + data @ 58 + w@-le inode-size ! + THEN + data @ 20 + l@-le blocks-per-group ! + data @ super-feature-incompat-64bit IF + data @ super-desc-size desc-size ! + ELSE + 20 desc-size ! + THEN + + \ Read the group descriptor table: + first-block @ 1+ block-size @ * + blocks-per-group @ + read-data + data @ group-descriptors ! + + \ We keep the group-descriptor memory area, so clear data pointer: + data off +; + +INSTANCE VARIABLE current-pos + +: read ( adr len -- actual ) + file-len @ current-pos @ - min \ can't go past end of file + current-pos @ block-size @ u/mod 4 * blocks @ + l@-le read-block + block-size @ over - rot min >r ( adr off r: len ) + data @ + swap r@ move r> dup current-pos +! ; +: read ( adr len -- actual ) + ( check if a file is selected, first ) + dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" ext2-files: read failed" + /string REPEAT 2drop r> ; +: seek ( lo hi -- status ) + lxjoin dup file-len @ > IF drop true EXIT THEN current-pos ! false ; +: load ( adr -- len ) + file-len @ read dup file-len @ <> ABORT" ext2-files: failed loading file" ; + +: .name ( adr -- ) dup 8 + swap 6 + c@ type ; +: read-dir ( inode# -- adr ) + read-inode read-block#s file-len @ alloc-mem + 0 0 seek ABORT" ext2-files read-dir: seek failed" + dup file-len @ read file-len @ <> ABORT" ext2-files read-dir: read failed" +; + +: .dir ( inode# -- ) + read-dir dup BEGIN 2dup file-len @ - > over l@-le tuck and WHILE + cr dup 8 0.r space read-inode .inode space space dup .name + dup 4 + w@-le + REPEAT 2drop file-len @ free-mem +; + +: (find-file) ( adr name len -- inode#|0 ) + 2>r dup BEGIN 2dup file-len @ - > over l@-le and WHILE + dup 8 + over 6 + c@ 2r@ str= IF 2r> 2drop nip l@-le EXIT THEN + dup 4 + w@-le + REPEAT 2drop 2r> 2drop 0 +; + +: find-file ( inode# name len -- inode#|0 ) + 2>r read-dir dup 2r> (find-file) swap file-len @ free-mem +; + +: find-path ( inode# name len -- inode#|0 ) + dup 0= IF 3drop 0 ." empty name " EXIT THEN + over c@ [char] \ = IF 1 /string ." slash " RECURSE EXIT THEN + [char] \ split 2>r find-file ?dup 0= IF + 2r> 2drop false ." not found " EXIT THEN + r@ 0<> IF 2r> ." more... " RECURSE EXIT THEN + 2r> 2drop ." got it " ; + +: close + inode @ inode-size @ free-mem + group-descriptors @ blocks-per-group @ free-mem + free-data + blocks @ ?dup IF #blocks @ 4 * free-mem THEN +; + +: open + 0 data ! 0 blocks ! 0 #blocks ! + do-super + inode-size @ alloc-mem inode ! + my-args nip 0= IF 0 0 ELSE + 2 my-args find-path ?dup 0= IF close false EXIT THEN THEN + read-inode read-block#s 0 0 seek 0= ; |