summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/slof/fs/packages/ext2-files.fs
blob: 262c64a34915ac21dbc1f0a289d4c0c6e9ea473b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
\ *****************************************************************************
\ * 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 group-desc-size
INSTANCE VARIABLE group-descriptors

: 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
INSTANCE VARIABLE #blocks
INSTANCE VARIABLE ^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
;

: read-block#s ( -- )
  blocks @ ?dup IF #blocks @ 4 * free-mem THEN
  inode @ 4 + l@-le file-len !
  file-len @ block-size @ // #blocks !
  #blocks @ 4 * alloc-mem blocks !
  blocks @ ^blocks !  #blocks @ #blocks-left !
  #blocks-left @ c min \ # direct blocks
  inode @ 28 + 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 ( inode# -- )
  1- inodes/group @ u/mod \ # in group, group #
  20 * group-descriptors @ + 8 + l@-le 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 ! ;

: 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 group-desc-size !

  \ Read the group descriptor table:
  first-block @ 1+ block-size @ *
  group-desc-size @
  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 @ group-desc-size @ 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= ;