blob: 716913714bc1f846ff243dd2387172bbe281948f (
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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= ;
|