Subversion Repositories Kolibri OS

Rev

Rev 5201 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4265 Serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Contains ext2 inode handling code.                           ;;
4
;;                                                              ;;
5
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
6
;; Distributed under the terms of the new BSD license.          ;;
7
;;                                                              ;;
8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9
 
10
;---------------------------------------------------------------------
11
; Receives block number from extent-based inode.
12
; Input:        ecx = number of block in inode
13
;               esi = address of extent header
14
;               ebp = pointer to EXTFS
15
; Output:       ecx = address of next block, if successful
16
;               eax = error code (0 implies no error)
17
;---------------------------------------------------------------------
18
ext4_block_recursive_search:
19
        cmp     word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
20
        jne     .fail
21
 
22
        movzx   ebx, [esi + EXT4_EXTENT_HEADER.eh_entries]
23
        add     esi, sizeof.EXT4_EXTENT_HEADER
24
        cmp     word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0
25
        je      .leaf_block     ;листовой ли это блок?
26
 
27
        ;не листовой блок, а индексный ; eax - ext4_extent_idx
28
        test    ebx, ebx
29
        jz      .fail               ;пустой индексный блок -> ошибка
30
 
31
        ;цикл по индексам экстентов
32
    @@:
33
        cmp     ebx, 1              ;у индексов не хранится длина,
34
        je      .end_search_index   ;поэтому, если остался последний - то это нужный
35
 
36
        cmp     ecx, [esi + EXT4_EXTENT_IDX.ei_block]
37
        jb      .fail
38
 
39
        cmp     ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
40
        jb      .end_search_index ;следующий дальше - значит текущий, то что нам нужен
41
 
42
        add     esi, sizeof.EXT4_EXTENT_IDX
43
        dec     ebx
44
        jmp     @B
45
 
46
    .end_search_index:
47
        ;ebp указывает на нужный extent_idx, считываем следующий блок
48
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
49
        mov     eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo]
50
        call    ext2_block_read
51
        test    eax, eax
52
        jnz     .fail
53
        mov     esi, ebx
54
        jmp     ext4_block_recursive_search ;рекурсивно прыгаем в начало
55
 
56
    .leaf_block:    ;листовой блок esi - ext4_extent
57
        ;цикл по экстентам
58
    @@:
59
        test    ebx, ebx
60
        jz      .fail       ;ни один узел не подошел - ошибка
61
 
62
        mov     edx, [esi + EXT4_EXTENT.ee_block]
63
        cmp     ecx, edx
64
        jb      .fail       ;если меньше, значит он был в предыдущих блоках -> ошибка
65
 
66
        movzx   edi, [esi + EXT4_EXTENT.ee_len]
67
        add     edx, edi
68
        cmp     ecx, edx
69
        jb      .end_search_extent     ;нашли нужный блок
70
 
71
        add     esi, sizeof.EXT4_EXTENT
72
        dec     ebx
73
        jmp     @B
74
 
75
    .end_search_extent:
76
        mov     edx, [esi + EXT4_EXTENT.ee_start_lo]
77
        sub     ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
78
        add     ecx, edx
79
        xor     eax, eax
80
        ret
81
 
82
    .fail:
83
        mov     eax, ERROR_FS_FAIL
84
        ret
85
 
86
;---------------------------------------------------------------------
87
; Frees triply indirect block.
88
; Input:        eax = triply indirect block.
89
;               [ebp + EXTFS.ext2_save_inode] = the inode.
90
; Output:       eax = error code.
91
;---------------------------------------------------------------------
92
ext2_inode_free_triply_indirect:
93
        push    ebx edx
94
 
95
        test    eax, eax
96
        jz      .success
97
        push    eax
98
        ; Read the triple indirect block.
99
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
100
        call    ext2_block_read
101
        test    eax, eax
102
        pop     eax
103
        jnz     .fail
104
 
105
        ; Free the triple indirect block.
106
        call    ext2_block_free
107
        test    eax, eax
108
        jnz     .fail
109
 
110
        mov     edx, ebx
111
        add     edx, [ebp + EXTFS.block_size]
112
 
113
    @@:
114
        mov     eax, [ebx]
115
        test    eax, eax
116
        jz      .success
117
 
118
        call    ext2_inode_free_doubly_indirect
119
        cmp     eax, 1
120
        je      .success
121
        cmp     eax, 0xFFFFFFFF
122
        je      .fail
123
 
124
        add     ebx, 4
125
        cmp     ebx, edx
126
        jb      @B
127
 
128
    .success:
129
        xor     eax, eax
130
    .ret:
131
        pop     edx ebx
132
        ret
133
 
134
    .fail:
135
        xor     eax, eax
136
        not     eax
137
        jmp     .ret
138
 
139
;---------------------------------------------------------------------
140
; Frees double indirect block.
141
; Input:        eax = double indirect block.
142
;               [ebp + EXTFS.ext2_save_inode] = the inode.
143
; Output:       eax = error code, 1 implies finished, ~0 implies error
144
;---------------------------------------------------------------------
145
ext2_inode_free_doubly_indirect:
146
        push    ebx edx
147
 
148
        test    eax, eax
149
        jz      .complete
150
        push    eax
151
        ; Read the double indirect block.
152
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
153
        call    ext2_block_read
154
        test    eax, eax
155
        pop     eax
156
        jnz     .fail
157
 
158
        call    ext2_block_free
159
        test    eax, eax
160
        jnz     .fail
161
 
162
        mov     edx, ebx
163
        add     edx, [ebp + EXTFS.block_size]
164
 
165
    @@:
166
        mov     eax, [ebx]
167
        test    eax, eax
168
        jz      .complete
169
 
170
        call    ext2_block_free
171
        test    eax, eax
172
        jnz     .fail
173
 
174
        add     ebx, 4
175
        cmp     ebx, edx
176
        jb      @B
177
 
178
    .success:
179
        xor     eax, eax
180
    .ret:
181
        pop     edx ebx
182
        ret
183
 
184
    .complete:
185
        xor     eax, eax
186
        inc     eax
187
        jmp     .ret
188
 
189
    .fail:
190
        xor     eax, eax
191
        not     eax
192
        jmp     .ret
193
 
194
;---------------------------------------------------------------------
195
; Frees all indirect blocks.
196
; Input:        ebp = pointer to EXTFS.
197
;               [ebp + EXTFS.ext2_save_inode] = the inode.
198
; Output:       eax = error code (0 implies no error)
199
;---------------------------------------------------------------------
200
ext2_inode_free_indirect_blocks:
201
        push    edi
202
 
203
        mov     edi, [ebp + EXTFS.ext2_save_inode]
204
 
205
        ; Free indirect block.
206
        mov     eax, [edi + EXT2_INODE_STRUC.i_block + 12*4]
207
        test    eax, eax
208
        jz      .success
209
 
210
        call    ext2_block_free
211
        test    eax, eax
212
        jnz     .fail
213
 
214
        mov     eax, [edi + EXT2_INODE_STRUC.i_block + 13*4]
215
        call    ext2_inode_free_doubly_indirect
216
        cmp     eax, 1
217
        je      .success
218
        cmp     eax, 0xFFFFFFFF
219
        je      .fail
220
 
221
        mov     eax, [edi + EXT2_INODE_STRUC.i_block + 14*4]
222
        call    ext2_inode_free_triply_indirect
223
        test    eax, eax
224
        jnz     .fail
225
 
226
    .success:
227
        xor     eax, eax
228
    .ret:
229
        pop     edi
230
        ret
231
 
232
    .fail:
233
        xor     eax, eax
234
        not     eax
235
        jmp     .ret
236
 
237
;---------------------------------------------------------------------
238
; Allocates block for inode.
239
; Input:        esi = address of inode
240
;               ebp = pointer to EXTFS.
241
; Output:       eax = error code (0 implies no error)
242
;---------------------------------------------------------------------
243
ext2_inode_calloc_block:
244
        push    ecx
245
 
246
        ; TODO: fix to have correct preference.
247
        mov     eax, EXT2_ROOT_INO
248
        call    ext2_block_calloc
249
        test    eax, eax
250
        jnz     .fail
251
 
252
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
253
        mov     eax, 2
254
        shl     eax, cl
255
        add     [esi + EXT2_INODE_STRUC.i_blocks], eax
256
 
257
    .success:
258
        xor     eax, eax
259
    .ret:
260
        pop     ecx
261
        ret
262
 
263
    .fail:
264
        xor     eax, eax
265
        not     eax
266
        jmp     .ret
267
 
268
;---------------------------------------------------------------------
269
; Sets block ID for indirect-addressing inode.
270
; Input:        ecx = index of block in inode
271
;               edi = block ID to set to
272
;               esi = address of inode
273
;               ebp = pointer to EXTFS.
274
; Output:       eax = error code (0 implies no error)
275
;---------------------------------------------------------------------
276
ext2_inode_set_block:
277
        push    ebx ecx edx
278
 
279
        ; 0 to 11: direct blocks.
280
        cmp     ecx, 12
281
        jb      .direct_block
282
 
283
        ; Indirect blocks
284
        sub     ecx, 12
285
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
286
        jb      .indirect_block
287
 
288
        ; Double indirect blocks.
289
        sub     ecx, [ebp + EXTFS.count_pointer_in_block]
290
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
291
        jb      .double_indirect_block
292
 
293
        ; Triple indirect blocks.
294
        sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
295
 
296
        ; Get triply-indirect block in temp_block.
297
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
298
        test    eax, eax
299
        jnz     @F
300
 
301
        call    ext2_inode_calloc_block
302
        test    eax, eax
303
        jnz     .fail_alloc
304
 
305
        mov     [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx
306
        mov     eax, ebx
307
 
308
    @@:
309
        push    eax
310
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
311
        call    ext2_block_read
312
        test    eax, eax
313
        jnz     .fail_alloc_4
314
 
315
        ; Get index in triply-indirect block.
316
        xor     edx, edx
317
        mov     eax, ecx
318
        div     [ebp + EXTFS.count_pointer_in_block_square]
319
 
320
        ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
321
        lea     ecx, [ebx + eax*4]
322
        mov     eax, [ebx + eax*4]
323
        test    eax, eax
324
        jnz     @F
325
 
326
        call    ext2_inode_calloc_block
327
        test    eax, eax
328
        jnz     .fail_alloc_4
329
 
330
        mov     [ecx], ebx
331
 
332
        mov     eax, [esp]
333
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
334
        call    ext2_block_write
335
        test    eax, eax
336
        jnz     .fail_alloc_4
337
 
338
        mov     eax, [ecx]
339
    @@:
340
        mov     [esp], eax
341
        call    ext2_block_read
342
        test    eax, eax
343
        jnz     .fail_alloc_4
344
 
345
        mov     eax, edx
346
        jmp     @F
347
 
348
    .double_indirect_block:
349
        ; Get doubly-indirect block.
350
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
351
        test    eax, eax
352
        jnz     .double_indirect_present
353
 
354
        call    ext2_inode_calloc_block
355
        test    eax, eax
356
        jnz     .fail_alloc
357
 
358
        mov     [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx
359
        mov     eax, ebx
360
 
361
    .double_indirect_present:
362
        ; Save block we're at.
363
        push    eax
364
 
365
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
366
        call    ext2_block_read
367
        test    eax, eax
368
        jnz     .fail_alloc_4
369
 
370
        mov     eax, ecx
371
    @@:
372
        xor     edx, edx
373
        div     [ebp + EXTFS.count_pointer_in_block]
374
 
375
        ; eax: index in doubly-indirect block, edx: index in indirect block.
376
        lea     ecx, [ebx + edx*4]
377
        push    ecx
378
 
379
        lea     ecx, [ebx + eax*4]
380
        cmp     dword[ecx], 0
381
        jne     @F
382
 
383
        call    ext2_inode_calloc_block
384
        test    eax, eax
385
        jnz     .fail_alloc_8
386
 
387
        mov     [ecx], ebx
388
 
389
        mov     eax, [esp + 4]
390
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
391
        call    ext2_block_write
392
        test    eax, eax
393
        jnz     .fail_alloc_8
394
 
395
    @@:
396
        mov     eax, [ecx]
397
        push    eax
398
        call    ext2_block_read
399
        test    eax, eax
400
        jnz     .fail_alloc_12
401
 
402
        pop     eax
403
        pop     ecx
404
        mov     [ecx], edi
405
        call    ext2_block_write
406
 
407
        add     esp, 4
408
        jmp     .return
409
 
410
    .indirect_block:
411
        ; Get index of indirect block.
412
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
413
        test    eax, eax
414
        jnz     @F
415
 
416
        call    ext2_inode_calloc_block
417
        test    eax, eax
418
        jnz     .fail_alloc
419
 
420
        mov     [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx
421
        mov     eax, ebx
422
 
423
    @@:
424
        push    eax
425
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
426
        call    ext2_block_read
427
        test    eax, eax
428
        jnz     .fail_alloc_4
429
 
430
        ; Get the block ID.
431
        mov     [ebx + ecx*4], edi
432
        pop     eax
433
        call    ext2_block_write
434
        jmp     .return
435
 
436
    .direct_block:
437
        mov     [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi
438
        xor     eax, eax
439
 
440
    .return:
441
        pop     edx ecx ebx
442
        ret
443
 
444
    .fail_alloc:
445
        xor     eax, eax
446
        not     eax
447
        jmp     .return
448
 
449
    .fail_alloc_12:
450
        add     esp, 4
451
    .fail_alloc_8:
452
        add     esp, 4
453
    .fail_alloc_4:
454
        add     esp, 4
455
        jmp     .fail_alloc
456
 
457
;---------------------------------------------------------------------
458
; Receives block ID from indirect-addressing inode.
459
; Input:        ecx = index of block in inode
460
;               esi = address of inode
461
;               ebp = pointer to EXTFS
462
; Output:       ecx = block ID, if successful
463
;               eax = error code (0 implies no error)
464
;---------------------------------------------------------------------
465
ext2_inode_get_block:
466
        ; If inode is extent-based, use ext4_block_recursive_search.
467
        test    [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
468
        jz      @F
469
 
470
        pushad
471
 
472
        ; Get extent header in EBP.
473
        add     esi, EXT2_INODE_STRUC.i_block
474
        call    ext4_block_recursive_search
475
        mov     PUSHAD_ECX, ecx
476
        mov     PUSHAD_EAX, eax
477
 
478
        popad
479
        ret
480
 
481
    @@:
482
        ; 0 to 11: direct blocks.
483
        cmp     ecx, 12
484
        jb      .get_direct_block
485
 
486
        ; Indirect blocks
487
        sub     ecx, 12
488
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
489
        jb      .get_indirect_block
490
 
491
        ; Double indirect blocks.
492
        sub     ecx, [ebp + EXTFS.count_pointer_in_block]
493
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
494
        jb      .get_double_indirect_block
495
 
496
        ; Triple indirect blocks.
497
        sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
498
        push    edx ebx
499
 
500
        ; Get triply-indirect block in temp_block.
501
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
502
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
503
        call    ext2_block_read
504
        test    eax, eax
505
        jnz     .fail
506
 
507
        ; Get index in triply-indirect block.
508
        xor     edx, edx
509
        mov     eax, ecx
510
        div     [ebp + EXTFS.count_pointer_in_block_square]
511
 
512
        ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
513
        mov     eax, [ebx + eax*4]
514
        test    eax, eax
515
        jz      .fail_triple_indirect_block
516
 
517
        call    ext2_block_read
518
        test    eax, eax
519
        jnz     .fail
520
 
521
        mov     eax, edx
522
        jmp     @F
523
 
524
    .get_double_indirect_block:
525
        push    edx ebx
526
 
527
        ; Get doubly-indirect block.
528
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
529
        test    eax, eax
530
        jz      .fail_double_indirect_block
531
 
532
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
533
        call    ext2_block_read
534
        test    eax, eax
535
        jnz     .fail
536
 
537
        mov     eax, ecx
538
    @@:
539
        xor     edx, edx
540
        div     [ebp + EXTFS.count_pointer_in_block]
541
 
542
        ; eax: index in doubly-indirect block, edx: index in indirect block.
543
        mov     eax, [ebx + eax*4]
544
        test    eax, eax
545
        jz      .fail_double_indirect_block
546
 
547
        call    ext2_block_read
548
        test    eax, eax
549
        jnz     .fail
550
 
551
        mov     ecx, [ebx + edx*4]
552
    .fail:
553
        pop     ebx edx
554
 
555
        ret
556
 
557
    .get_indirect_block:
558
        push    ebx
559
 
560
        ; Get index of indirect block.
561
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
562
        test    eax, eax
563
        jz      .fail_indirect_block
564
 
565
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
566
        call    ext2_block_read
567
        test    eax, eax
568
        jnz     @F
569
 
570
        mov     ecx, [ebx + ecx*4]
571
    @@:
572
        pop     ebx
573
 
574
        ret
575
 
576
    .get_direct_block:
577
        mov     ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
578
        xor     eax, eax
579
 
580
        ret
581
 
582
    .fail_indirect_block:
583
        pop     ebx
584
 
585
    .fail_triple_indirect_block:
586
        xor     eax, eax
587
        xor     ecx, ecx
588
        ret
589
 
590
    .fail_double_indirect_block:
591
        pop     ebx edx
592
        jmp     .fail_triple_indirect_block
593
 
594
;---------------------------------------------------------------------
595
; Get block containing inode.
596
; Input:        eax = inode number.
597
;               ebp = pointer to EXTFS.
598
; Output:       ebx = block (hard disk) containing inode.
599
;               edx = index inside block.
600
;               eax = error code (0 implies no error)
601
;---------------------------------------------------------------------
602
ext2_read_block_of_inode:
603
        pushad
604
 
605
        dec     eax
606
        xor     edx, edx
607
 
608
        ; EAX = block group.
609
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
610
 
611
        push    edx                             ; Index in group.
612
 
613
        mov     edx, 32
614
        mul     edx                             ; Get index of descriptor in global_desc_table.
615
 
616
        ; eax: inode group offset relative to global descriptor table start
617
        ; Find the block this block descriptor is in.
618
        div     [ebp + EXTFS.block_size]
619
        add     eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
620
        inc     eax
621
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
622
        call    ext2_block_read
623
        test    eax, eax
624
        jnz     .return
625
 
626
        add     ebx, edx                        ; edx: local index of descriptor inside block
627
        mov     eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]   ; Block number of inode table - in ext2 terms.
628
        mov     ecx, [ebp + EXTFS.log_block_size]
629
        shl     eax, cl
630
 
631
        ; eax: points to inode table on HDD.
632
        mov     esi, eax
633
 
634
        ; Add local address of inode.
635
        pop     eax
636
        mov     ecx, [ebp + EXTFS.inode_size]
637
        mul     ecx                             ; (index * inode_size)
638
 
639
        mov     ebp, 512
640
        div     ebp                             ; Divide by hard disk block size.
641
 
642
        add     eax, esi                        ; Found block to read.
643
        mov     ebx, eax                        ; Get it inside ebx.
644
 
645
        xor     eax, eax
646
    .return:
647
        mov     PUSHAD_EAX, eax
648
        mov     PUSHAD_EBX, ebx
649
        mov     PUSHAD_EDX, edx
650
 
651
        popad
652
        ret
653
 
654
;---------------------------------------------------------------------
655
; Sets content of inode by number.
656
; Input:        eax = inode number.
657
;               ebx = address from where to write inode content.
658
;               ebp = pointer to EXTFS.
659
; Output:       eax = error code (0 implies no error)
660
;---------------------------------------------------------------------
661
ext2_inode_write:
662
        push    edx edi esi ecx ebx
663
        mov     esi, ebx
664
 
665
        ; Ext2 actually stores time of modification of inode in ctime.
666
        lea     edi, [ebx + EXT2_INODE_STRUC.i_ctime]
667
        call    current_unix_time
668
 
669
        ; Get block where inode is situated.
670
        call    ext2_read_block_of_inode
671
        test    eax, eax
672
        jnz     .error
673
 
674
        mov     eax, ebx                        ; Get block into EAX.
675
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
676
 
677
        mov     ecx, eax                        ; Save block.
678
        call    fs_read32_sys
679
        test    eax, eax
680
        jz      @F
681
 
682
    .error:
683
        mov     eax, ERROR_DEVICE
684
        jmp     .return
685
 
686
    @@:
687
        mov     eax, ecx
688
        mov     ecx, [ebp + EXTFS.inode_size]
689
        mov     edi, edx                        ; The index into the block.
690
        add     edi, ebx
691
        rep movsb
692
 
693
        ; Write the block.
694
        call    fs_write32_sys
695
 
696
    .return:
697
        pop     ebx ecx esi edi edx
698
        ret
699
 
700
;---------------------------------------------------------------------
701
; Get content of inode by number.
702
; Input:        eax = inode number.
703
;               ebx = address where to store inode content.
704
;               ebp = pointer to EXTFS.
705
; Output:       eax = error code (0 implies no error)
706
;---------------------------------------------------------------------
707
ext2_inode_read:
708
        push    edx edi esi ecx ebx
709
        mov     edi, ebx
710
 
711
        ; Get block where inode is situated.
712
        call    ext2_read_block_of_inode
713
        test    eax, eax
714
        jnz     .error
715
 
716
        mov     eax, ebx                        ; Get block into EAX.
717
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
718
        call    fs_read32_sys
719
        test    eax, eax
720
        jz      @F
721
 
722
    .error:
723
        mov     eax, ERROR_DEVICE
724
        jmp     .return
725
 
726
    @@:
727
        mov     ecx, [ebp + EXTFS.inode_size]
728
        mov     esi, edx                        ; The index into the inode.
729
        add     esi, ebx
730
        rep movsb
731
 
732
        xor     eax, eax
733
    .return:
734
        pop     ebx ecx esi edi edx
735
        ret
736
 
737
;---------------------------------------------------------------------
738
; Seek inode from the path.
739
; Input:        esi + [esp + 4] = name.
740
;               ebp = pointer to EXTFS.
741
; Output:       eax = error code (0 implies no error)
742
;               esi = inode number.
743
;                dl = first byte of file/folder name.
744
;                     [ext2_data.ext2_save_inode] stores the inode.
745
;---------------------------------------------------------------------
746
ext2_inode_find:
747
        mov     edx, [ebp + EXTFS.root_inode]
748
 
749
        ; Check for empty root.
750
        cmp     [edx + EXT2_INODE_STRUC.i_blocks], 0
751
        je      .error_empty_root
752
 
753
        ; Check for root.
754
        cmp     byte[esi], 0
755
        jne     .next_path_part
756
 
757
        push    edi ecx
758
        mov     esi, [ebp + EXTFS.root_inode]
759
        mov     edi, [ebp + EXTFS.ext2_save_inode]
760
        mov     ecx, [ebp + EXTFS.inode_size]
761
        rep movsb
762
        pop     ecx edi
763
 
764
        xor     eax, eax
765
        xor     dl, dl
766
        mov     esi, EXT2_ROOT_INO
767
        ret     4
768
 
769
    .next_path_part:
770
        push    [edx + EXT2_INODE_STRUC.i_blocks]
771
        xor     ecx, ecx
772
 
773
    .folder_block_cycle:
774
        push    ecx
775
        xchg    esi, edx
776
        call    ext2_inode_get_block
777
        xchg    esi, edx
778
        test    eax, eax
779
        jnz     .error_get_inode_block
780
 
781
        mov     eax, ecx
782
        mov     ebx, [ebp + EXTFS.ext2_save_block]              ; Get directory records from directory.
783
        call    ext2_block_read
784
        test    eax, eax
785
        jnz     .error_get_block
786
 
787
        push    esi
788
        push    edx
789
        call    ext2_block_find_parent
790
        pop     edx
791
        pop     edi ecx
792
 
793
        cmp     edi, esi                                        ; Did something match?
794
        je      .next_folder_block                              ; No, move to next block.
795
 
796
        cmp     byte [esi], 0                                   ; Reached the "end" of path successfully.
797
        jnz     @F
798
        cmp     dword[esp + 8], 0
799
        je      .get_inode_ret
800
        mov     esi, [esp + 8]
801
        mov     dword[esp + 8], 0
802
 
803
    @@:
804
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]
805
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
806
        call    ext2_inode_read
807
        test    eax, eax
808
        jnz     .error_get_inode
809
 
810
        movzx   eax, [ebx + EXT2_INODE_STRUC.i_mode]
811
        and     eax, EXT2_S_IFMT                                ; Get the mask.
812
        cmp     eax, EXT2_S_IFDIR
813
        jne     .not_found                                      ; Matched till part, but directory entry we got doesn't point to folder.
814
 
815
        pop     ecx                                             ; Stack top contains number of blocks.
816
        mov     edx, ebx
817
        jmp     .next_path_part
818
 
819
    .next_folder_block:
820
        ; Next block in current folder.
821
        pop     eax                                             ; Get blocks counter.
822
        sub     eax, [ebp + EXTFS.count_block_in_block]
823
        jle     .not_found
824
 
825
        push    eax
826
        inc     ecx
827
        jmp     .folder_block_cycle
828
 
829
    .not_found:
830
        mov     eax, ERROR_FILE_NOT_FOUND
831
        ret     4
832
 
833
    .get_inode_ret:
834
        pop     ecx                                             ; Stack top contains number of blocks.
835
 
836
        mov     dl, [ebx + EXT2_DIR_STRUC.name]                 ; First character of file-name.
837
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]
838
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
839
        mov     esi, eax
840
 
841
        ; If we can't get the inode, eax contains the error.
842
        call    ext2_inode_read
843
        ret     4
844
 
845
    .error_get_inode_block:
846
    .error_get_block:
847
        pop     ecx
848
    .error_get_inode:
849
        pop     ebx
850
    .error_empty_root:
851
        mov     eax, ERROR_FS_FAIL
852
        ret     4
853
 
854
;---------------------------------------------------------------------
855
; Seeks parent inode from path.
856
; Input:        esi = path.
857
;               ebp = pointer to EXTFS.
858
; Output:       eax = error code.
859
;               esi = inode.
860
;               edi = pointer to file name.
861
;---------------------------------------------------------------------
862
ext2_inode_find_parent:
863
        push    esi
864
        xor     edi, edi
865
 
866
    .loop:
867
        cmp     byte[esi], '/'
868
        jne     @F
869
 
870
        mov     edi, esi
871
        inc     esi
872
        jmp     .loop
873
 
874
    @@:
875
        inc     esi
876
        cmp     byte[esi - 1], 0
877
        jne     .loop
878
 
879
        ; If it was just a filename (without any additional directories),
880
        ; use the last byte as "parent path".
881
        cmp     edi, 0
882
        jne     @F
883
 
884
        pop     edi
885
        dec     esi
886
        jmp     .get_inode
887
 
888
        ; It had some additional directories, so handle it that way.
889
    @@:
890
        mov     byte[edi], 0
891
        inc     edi
892
        pop     esi
893
 
894
    .get_inode:
895
        push    ebx edx
896
        stdcall ext2_inode_find, 0
897
        pop     edx ebx
898
 
899
    .return:
900
        ret
901
 
902
;---------------------------------------------------------------------
903
; Link an inode.
904
; Input:        eax = inode on which to link.
905
;               ebx = inode to link.
906
;                dl = file type.
907
;               esi = name.
908
;               ebp = pointer to EXTFS.
909
; Output:       eax = error code.
910
;---------------------------------------------------------------------
911
ext2_inode_link:
912
        push    eax
913
        push    esi edi ebx ecx edx
914
 
915
        ; Get string length, and then directory entry structure size.
916
        call    strlen
917
        add     ecx, 8
918
 
919
        push    esi ebx ecx
920
 
921
        xor     ecx, ecx
922
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
923
        mov     ebx, esi
924
 
925
        call    ext2_inode_read
926
        test    eax, eax
927
        jnz     .error_inode_read
928
 
929
        ; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)).
930
        ; Note that i_blocks contains number of reserved 512B blocks, which is why we've to
931
        ; find out the ext2 blocks.
932
        mov     eax, 2
933
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
934
        shl     eax, cl
935
        mov     ecx, eax
936
 
937
        mov     eax, [esi + EXT2_INODE_STRUC.i_blocks]
938
        xor     edx, edx
939
 
940
        div     ecx
941
 
942
        ; EAX is the maximum index inside i_block we can go.
943
        push    eax
944
        push    dword 0
945
 
946
        ; ECX contains the "block inside i_block" index.
947
        xor     ecx, ecx
948
    @@:
949
        call    ext2_inode_get_block
950
        test    eax, eax
951
        jnz     .error_get_inode_block
952
        test    ecx, ecx
953
        jz      .alloc_block        ; We've got no block here, so allocate one.
954
 
955
        push    ecx                 ; Save block number.
956
 
957
        mov     eax, ecx
958
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
959
        call    ext2_block_read
960
        test    eax, eax
961
        jnz     .error_block_read
962
 
963
        ; Try to find free space in current block.
964
        mov     ecx, [esp + 8]
965
        call    ext2_block_find_fspace
966
        test    eax, eax
967
        jz      .found
968
 
969
        cmp     eax, 0x00000001
970
        jne     .next_iter
971
 
972
        ; This block wasn't linking to the next block, so fix that, and use the next one.
973
        ; Write the block.
974
        pop     eax
975
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
976
        call    ext2_block_write
977
        test    eax, eax
978
        jnz     .error_get_inode_block
979
 
980
        inc     dword [esp]
981
        mov     ecx, [esp]
982
        call    ext2_inode_get_block
983
        test    eax, eax
984
        jnz     .error_get_inode_block
985
 
986
        test    ecx, ecx
987
        jz      .alloc_block
988
 
989
        ; If there was a block there, prepare it for our use!
990
        push    ecx
991
        jmp     .prepare_block
992
 
993
    .next_iter:
994
        add     esp, 4
995
 
996
        inc     dword [esp]
997
        mov     ecx, [esp]
998
        cmp     ecx, [esp + 4]
999
        jbe     @B
1000
 
1001
    .alloc_block:
1002
        mov     eax, [esp + 12]     ; Get inode ID of what we're linking.
1003
        call    ext2_block_calloc
1004
        test    eax, eax
1005
        jnz     .error_get_inode_block
1006
 
1007
        mov     ecx, [esp]          ; Get the index of it inside the inode.
1008
        mov     edi, ebx            ; And what to set to.
1009
        call    ext2_inode_set_block
1010
        test    eax, eax
1011
        jnz     .error_get_inode_block
1012
 
1013
        ; Update i_size.
1014
        mov     eax, [ebp + EXTFS.block_size]
1015
        add     [esi + EXT2_INODE_STRUC.i_size], eax
1016
 
1017
        ; Update i_blocks.
1018
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
1019
        mov     eax, 2
1020
        shl     eax, cl
1021
        add     [esi + EXT2_INODE_STRUC.i_blocks], eax
1022
 
1023
        ; Write the inode.
1024
        mov     eax, [esp + 40]
1025
        mov     ebx, esi
1026
        call    ext2_inode_write
1027
        test    eax, eax
1028
        jnz     .error_get_inode_block
1029
 
1030
        push    edi                 ; Save the block we just allocated.
1031
 
1032
    ; If we've allocated/using-old-block outside of loop, prepare it.
1033
    .prepare_block:
1034
        mov     eax, [esp]
1035
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1036
        call    ext2_block_read
1037
        test    eax, eax
1038
        jnz     .error_block_read
1039
 
1040
        mov     edi, ebx
1041
        mov     eax, [ebp + EXTFS.block_size]
1042
        mov     [edi + EXT2_DIR_STRUC.rec_len], ax
1043
 
1044
    .found:
1045
        pop     edx
1046
        add     esp, 8
1047
        pop     ecx ebx esi
1048
 
1049
        push    ebx
1050
        mov     [edi], ebx          ; Save inode.
1051
 
1052
        mov     eax, [esp + 4]      ; Get EDX off the stack -- contains the file_type.
1053
        cmp     [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV
1054
        je      .name
1055
 
1056
        ; Set the file-type.
1057
        mov     [edi + EXT2_DIR_STRUC.file_type], al
1058
 
1059
    .name:
1060
        ; Save name.
1061
        sub     ecx, 8
1062
        mov     [edi + EXT2_DIR_STRUC.name_len], cl
1063
        add     edi, 8
1064
        rep movsb
1065
 
1066
        ; Write block.
1067
        mov     eax, edx
1068
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1069
        call    ext2_block_write
1070
        test    eax, eax
1071
        jnz     .error_block_write
1072
 
1073
        mov     eax, [esp]
1074
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1075
        call    ext2_inode_read
1076
        test    eax, eax
1077
        jnz     .error_block_write
1078
 
1079
        pop     eax
1080
        inc     [ebx + EXT2_INODE_STRUC.i_links_count]
1081
        call    ext2_inode_write
1082
        test    eax, eax
1083
        jnz     .error
1084
 
1085
        xor     eax, eax
1086
    .ret:
1087
        pop     edx ecx ebx edi esi
1088
        add     esp, 4
1089
        ret
1090
 
1091
    .error_block_read:
1092
        add     esp, 4
1093
    .error_get_inode_block:
1094
        add     esp, 8
1095
    .error_inode_read:
1096
        add     esp, 8
1097
    .error_block_write:
1098
        add     esp, 4
1099
    .error:
1100
        xor     eax, eax
1101
        not     eax
1102
        jmp     .ret
1103
 
1104
;---------------------------------------------------------------------
1105
; Unlink an inode.
1106
; Input:        eax = inode from which to unlink.
1107
;               ebx = inode to unlink.
1108
;               ebp = pointer to EXTFS.
1109
; Output:       eax = number of links to inode, after unlinking (0xFFFFFFFF implies error)
1110
;---------------------------------------------------------------------
1111
ext2_inode_unlink:
1112
        push    ebx ecx edx esi edi
1113
 
1114
        push    ebx
1115
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1116
        call    ext2_inode_read
1117
 
1118
        test    eax, eax
1119
        jnz     .fail_get_inode
1120
 
1121
        ; The index into the inode block data.
1122
        push    dword 0
1123
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1124
 
1125
    .loop:
1126
        mov     ecx, [esp]
1127
        call    ext2_inode_get_block
1128
 
1129
        test    eax, eax
1130
        jnz     .fail_loop
1131
        test    ecx, ecx
1132
        jz      .fail_loop
1133
 
1134
        mov     eax, ecx
1135
        mov     edi, eax
1136
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1137
        call    ext2_block_read
1138
        test    eax, eax
1139
        jnz     .fail_loop
1140
 
1141
    ; edi -> block.
1142
    .first_dir_entry:
1143
        mov     eax, [esp + 4]
1144
        cmp     [ebx], eax
1145
        jne     @F
1146
 
1147
        mov     dword[ebx], 0                               ; inode.
1148
        mov     word[ebx + 6], 0                            ; name_len + file_type.
1149
        jmp     .write_block
1150
 
1151
    @@:
1152
        mov     edx, ebx
1153
        add     edx, [ebp + EXTFS.block_size]
1154
        push    edx
1155
 
1156
        mov     edx, ebx
1157
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1158
        add     ebx, ecx
1159
 
1160
    .dir_entry:
1161
        cmp     [ebx], eax
1162
        jne     @F
1163
 
1164
        mov     cx, [ebx + EXT2_DIR_STRUC.rec_len]
1165
        add     [edx + EXT2_DIR_STRUC.rec_len], cx
1166
        add     esp, 4
1167
        jmp     .write_block
1168
 
1169
    @@:
1170
        mov     edx, ebx
1171
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1172
 
1173
        ; If it's a zero length entry, error.
1174
        test    ecx, ecx
1175
        jz      .fail_inode
1176
 
1177
        add     ebx, ecx
1178
 
1179
        cmp     ebx, [esp]
1180
        jb      .dir_entry
1181
 
1182
        add     esp, 4
1183
        inc     dword[esp]
1184
        jmp     .loop
1185
 
1186
    .write_block:
1187
        mov     eax, edi
1188
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1189
        call    ext2_block_write
1190
        test    eax, eax
1191
        jnz     .fail_loop
1192
 
1193
        add     esp, 4
1194
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1195
        mov     eax, [esp]
1196
        call    ext2_inode_read
1197
        test    eax, eax
1198
        jnz     .fail_get_inode
1199
 
1200
        dec     word[ebx + EXT2_INODE_STRUC.i_links_count]
1201
        movzx   eax, word[ebx + EXT2_INODE_STRUC.i_links_count]
1202
        push    eax
1203
 
1204
        mov     eax, [esp + 4]
1205
        call    ext2_inode_write
1206
        test    eax, eax
1207
        jnz     .fail_loop
1208
 
1209
        pop     eax
1210
        add     esp, 4
1211
    .return:
1212
        pop     edi esi edx ecx ebx
1213
        ret
1214
 
1215
    .fail_inode:
1216
        add     esp, 4
1217
 
1218
    .fail_loop:
1219
        add     esp, 4
1220
 
1221
    .fail_get_inode:
1222
        add     esp, 4
1223
 
1224
    .fail:
1225
        xor     eax, eax
1226
        not     eax
1227
        jmp     .return
1228
 
1229
;---------------------------------------------------------------------
1230
; Checks if a directory is empty.
1231
; Input:        ebx = inode to check.
1232
;               ebp = pointer to EXTFS.
1233
;               [EXTFS.ext2_save_inode] = points to saved inode.
1234
; Output:       eax = 0 signifies empty directory.
1235
;---------------------------------------------------------------------
1236
ext2_dir_empty:
1237
        push    ebx ecx edx
1238
 
1239
        ; The index into the inode block data.
1240
        push    dword 0
1241
        mov     esi, [ebp + EXTFS.ext2_save_inode]
1242
 
1243
    .loop:
1244
        mov     ecx, [esp]
1245
        call    ext2_inode_get_block
1246
 
1247
        ; Treat a failure as not-empty.
1248
        test    eax, eax
1249
        jnz     .not_empty
1250
        test    ecx, ecx
1251
        jz      .empty
1252
 
1253
        mov     eax, ecx
1254
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1255
        call    ext2_block_read
1256
        test    eax, eax
1257
        jnz     .not_empty
1258
 
1259
        mov     edx, ebx
1260
        add     edx, [ebp + EXTFS.block_size]
1261
 
1262
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1263
        add     ebx, ecx
1264
 
1265
    .dir_entry:
1266
        ; Process entry.
1267
        cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 1
1268
        jne     @F
1269
 
1270
        cmp     byte[ebx + EXT2_DIR_STRUC.name], '.'
1271
        jne     .not_empty
1272
 
1273
    @@:
1274
        cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 2
1275
        jne     .not_empty
1276
 
1277
        cmp     word[ebx + EXT2_DIR_STRUC.name], '..'
1278
        jne     .not_empty
1279
 
1280
    @@:
1281
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1282
        add     ebx, ecx
1283
 
1284
        cmp     ebx, edx
1285
        jb      .dir_entry
1286
 
1287
        inc     dword[esp]
1288
        jmp     .loop
1289
 
1290
    .empty:
1291
        xor     eax, eax
1292
    .return:
1293
        add     esp, 4
1294
        pop     edx ecx ebx
1295
        ret
1296
 
1297
    .not_empty:
1298
        xor     eax, eax
1299
        not     eax
1300
        jmp     .return
1301
 
1302
;---------------------------------------------------------------------
1303
; Gets the block group's inode bitmap.
1304
; Input:        eax = block group.
1305
; Output:       eax = if zero, error; else, points to block group descriptor.
1306
;               ebx = inode bitmap's block (hard disk).
1307
;---------------------------------------------------------------------
1308
ext2_bg_read_inode_bitmap:
1309
        push    ecx
1310
 
1311
        call    ext2_bg_read_desc
1312
        test    eax, eax
1313
        jz      .fail
1314
 
1315
        mov     ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms.
1316
 
1317
    .return:
1318
        pop     ecx
1319
        ret
1320
 
1321
    .fail:
1322
        xor     eax, eax
1323
        jmp     .return
1324
 
1325
;---------------------------------------------------------------------
1326
; Allocates a inode.
1327
; Input:        eax = inode ID for "preference".
1328
;               ebp = pointer to EXTFS.
1329
; Output:       Inode marked as set in inode group.
1330
;               eax = error code.
1331
;               ebx = inode ID.
1332
;---------------------------------------------------------------------
1333
ext2_inode_alloc:
1334
        push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count]
1335
        push    EXT2_BLOCK_GROUP_DESC.free_inodes_count
1336
        push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1337
 
1338
        lea     ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count]
1339
        push    ebx
1340
 
1341
        push    ext2_bg_read_inode_bitmap
1342
 
1343
        call    ext2_resource_alloc
1344
 
1345
        ; Inode table starts with 1.
1346
        inc     ebx
1347
 
1348
        ret
1349
 
1350
;---------------------------------------------------------------------
1351
; Frees a inode.
1352
; Input:        eax = inode ID.
1353
;               ebp = pointer to EXTFS.
1354
; Output:       inode marked as free in block group.
1355
;               eax = error code.
1356
;---------------------------------------------------------------------
1357
ext2_inode_free:
1358
        push    edi ecx
1359
 
1360
        ; Inode table starts with 1.
1361
        dec     eax
1362
 
1363
        mov     edi, ext2_bg_read_inode_bitmap
1364
        xor     ecx, ecx
1365
        inc     cl
1366
        call    ext2_resource_free
1367
 
1368
        pop     ecx edi
1369
        ret
1370
 
1371
;---------------------------------------------------------------------
1372
; Blanks a particular entry in an inode.
1373
; Input:        eax = index into block.
1374
;               edx = inode.
1375
;               ebp = pointer to EXTFS.
1376
;               [ebp + EXTFS.ext2_temp_inode] = the inode.
1377
; Output:       eax = error code.
1378
;---------------------------------------------------------------------
1379
ext2_inode_blank_entry:
1380
        push    ebx ecx edx edi esi
1381
 
1382
        mov     edi, eax
1383
 
1384
        mov     ecx, eax
1385
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1386
        call    ext2_inode_get_block
1387
        test    eax, eax
1388
        jnz     .error
1389
 
1390
        test    ecx, ecx
1391
        jz      .allocate
1392
 
1393
        mov     edx, ecx
1394
        mov     ecx, [ebp + EXTFS.block_size]
1395
        mov     edi, [ebp + EXTFS.ext2_temp_block]
1396
        xor     eax, eax
1397
        rep stosb
1398
 
1399
        mov     eax, edx
1400
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1401
        call    ext2_block_write
1402
        test    eax, eax
1403
        jnz     .error
1404
 
1405
        jmp     .success
1406
 
1407
    ; Need to allocate a block.
1408
    .allocate:
1409
        mov     eax, edx
1410
        call    ext2_block_calloc
1411
        test    eax, eax
1412
        jnz     .error
1413
 
1414
        mov     ecx, edi
1415
        mov     edi, ebx
1416
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1417
        call    ext2_inode_set_block
1418
        test    eax, eax
1419
        jnz     .error
1420
 
1421
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
1422
        mov     eax, 2
1423
        shl     eax, cl
1424
        add     [esi + EXT2_INODE_STRUC.i_blocks], eax
1425
 
1426
    .success:
1427
        xor     eax, eax
1428
 
1429
    .ret:
1430
        pop     esi edi edx ecx ebx
1431
        ret
1432
 
1433
    .error:
1434
        xor     eax, eax
1435
        not     eax
1436
        jmp     .ret
1437
 
1438
;---------------------------------------------------------------------
1439
; Frees a particular entry in an inode.
1440
; Input:        eax = index into block.
1441
;               ebp = pointer to EXTFS.
1442
;               [ebp + EXTFS.ext2_temp_inode] = the inode.
1443
; Output:       eax = error code.
1444
;---------------------------------------------------------------------
1445
ext2_inode_free_entry:
1446
        push    ebx ecx edi esi
1447
 
1448
        mov     edi, eax
1449
 
1450
        mov     ecx, eax
1451
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1452
        call    ext2_inode_get_block
1453
        test    eax, eax
1454
        jnz     .error
1455
 
1456
        test    ecx, ecx
1457
        jz      .success
1458
 
1459
        mov     eax, ecx
1460
        call    ext2_block_free
1461
        test    eax, eax
1462
        jnz     .error
1463
 
1464
        mov     ecx, edi
1465
        xor     edi, edi
1466
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1467
        call    ext2_inode_set_block
1468
 
1469
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
1470
        mov     eax, 2
1471
        shl     eax, cl
1472
        sub     [esi + EXT2_INODE_STRUC.i_blocks], eax
1473
 
1474
    .success:
1475
        xor     eax, eax
1476
 
1477
    .ret:
1478
        pop     esi edi ecx ebx
1479
        ret
1480
 
1481
    .error:
1482
        xor     eax, eax
1483
        not     eax
1484
        jmp     .ret
1485
 
1486
;---------------------------------------------------------------------
1487
; Reads a particular entry from an inode.
1488
; Input:        eax = index into block.
1489
;               ebp = pointer to EXTFS.
1490
;               [ebp + EXTFS.ext2_temp_inode] = the inode.
1491
; Output:       eax = error code.
1492
;               [ebp + EXTFS.ext2_save_block] = the read block.
1493
;---------------------------------------------------------------------
1494
ext2_inode_read_entry:
1495
        push    ebx ecx edx esi
1496
 
1497
        mov     ecx, eax
1498
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1499
        call    ext2_inode_get_block
1500
        test    eax, eax
1501
        jnz     .error
1502
 
1503
        test    ecx, ecx
1504
        jz      .error
1505
 
1506
        mov     eax, ecx
1507
        mov     ebx, [ebp + EXTFS.ext2_save_block]
1508
        call    ext2_block_read
1509
        test    eax, eax
1510
        jnz     .error
1511
 
1512
    .ret:
1513
        pop     esi edx ecx ebx
1514
        ret
1515
 
1516
    .error:
1517
        xor     eax, eax
1518
        not     eax
1519
        jmp     .ret
1520
 
1521
;---------------------------------------------------------------------
1522
; Writes a particular entry from an inode.
1523
; Input:        eax = index into block.
1524
;               ebp = pointer to EXTFS.
1525
;               [ebp + EXTFS.ext2_temp_inode] = the inode.
1526
;               [ebp + EXTFS.ext2_save_block] = the block to write.
1527
; Output:       eax = error code.
1528
;---------------------------------------------------------------------
1529
ext2_inode_write_entry:
1530
        push    ebx ecx edx esi
1531
 
1532
        mov     ecx, eax
1533
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
1534
        call    ext2_inode_get_block
1535
        test    eax, eax
1536
        jnz     .error
1537
 
1538
        test    ecx, ecx
1539
        jz      .error
1540
 
1541
        mov     eax, ecx
1542
        mov     ebx, [ebp + EXTFS.ext2_save_block]
1543
        call    ext2_block_write
1544
        test    eax, eax
1545
        jnz     .error
1546
 
1547
    .ret:
1548
        pop     esi edx ecx ebx
1549
        ret
1550
 
1551
    .error:
1552
        xor     eax, eax
1553
        not     eax
1554
        jmp     .ret
1555
 
1556
;---------------------------------------------------------------------
1557
; Extends inode to said size.
1558
; Input:        eax = inode ID.
1559
;               ecx = size to extend to.
1560
;               ebp = pointer to EXTFS.
1561
; Output:       eax = error code.
1562
;---------------------------------------------------------------------
1563
ext2_inode_extend:
1564
        push    ebx ecx edx esi edi
1565
 
1566
        ; Save the inode.
1567
        push    eax
1568
 
1569
        ; Read the inode.
1570
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1571
        call    ext2_inode_read
1572
        test    eax, eax
1573
        jnz     .error
1574
 
1575
        mov     eax, [ebx + EXT2_INODE_STRUC.i_size]
1576
        cmp     eax, ecx
1577
        jge     .success
1578
 
1579
        ; Save the size of the inode.
1580
        push    eax
1581
 
1582
        ; ECX contains the size we've to write.
1583
        sub     ecx, eax
1584
        xor     edx, edx
1585
        div     [ebp + EXTFS.block_size]
1586
 
1587
        test    edx, edx
1588
        jz      .start_aligned
1589
 
1590
        ; Start isn't aligned, so deal with the non-aligned bytes.
1591
        mov     esi, [ebp + EXTFS.block_size]
1592
        sub     esi, edx
1593
 
1594
        cmp     esi, ecx
1595
        jbe     @F
1596
 
1597
        ; If the size to entend to fits in current block, limit to that.
1598
        mov     esi, ecx
1599
 
1600
    @@:
1601
        ; Clear ESI bytes, in EAX indexed block.
1602
        push    eax
1603
        call    ext2_inode_read_entry
1604
        test    eax, eax
1605
        pop     eax
1606
        jnz     .error_inode_size
1607
 
1608
        push    eax ecx
1609
 
1610
        xor     eax, eax
1611
        mov     ecx, esi
1612
        mov     edi, ebx
1613
        add     edi, edx
1614
 
1615
        rep stosb
1616
 
1617
        pop     ecx eax
1618
 
1619
        ; Write the block.
1620
        call    ext2_inode_write_entry
1621
        test    eax, eax
1622
        jnz     .error_inode_size
1623
 
1624
        add     [esp], esi
1625
        sub     ecx, esi
1626
        jz      .write_inode
1627
 
1628
    .start_aligned:
1629
        cmp     ecx, [ebp + EXTFS.block_size]
1630
        jb      @F
1631
 
1632
        mov     eax, [esp]
1633
        xor     edx, edx
1634
        div     [ebp + EXTFS.block_size]
1635
 
1636
        mov     edx, [esp + 4]
1637
        call    ext2_inode_blank_entry
1638
 
1639
        test    eax, eax
1640
        jnz     .error_inode_size
1641
 
1642
        mov     eax, [ebp + EXTFS.block_size]
1643
        sub     ecx, eax
1644
        add     [esp], eax
1645
        jmp     .start_aligned
1646
 
1647
    ; Handle the remaining bytes.
1648
    @@:
1649
        test    ecx, ecx
1650
        jz      .write_inode
1651
 
1652
        mov     eax, [esp]
1653
        xor     edx, edx
1654
        div     [ebp + EXTFS.block_size]
1655
 
1656
        mov     edx, [esp + 4]
1657
        call    ext2_inode_blank_entry
1658
 
1659
        test    eax, eax
1660
        jnz     .error_inode_size
1661
        add     [esp], ecx
1662
 
1663
    .write_inode:
1664
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1665
        pop     eax
1666
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1667
        mov     eax, [esp]
1668
        call    ext2_inode_write
1669
 
1670
        test    eax, eax
1671
        jnz     .error
1672
 
1673
    .success:
1674
        xor     eax, eax
1675
 
1676
    .ret:
1677
        add     esp, 4
1678
 
1679
        pop     edi esi edx ecx ebx
1680
        ret
1681
 
1682
    .error_inode_size:
1683
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1684
        pop     eax
1685
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1686
        mov     eax, [esp]
1687
        call    ext2_inode_write
1688
 
1689
    .error:
1690
        xor     eax, eax
1691
        not     eax
1692
        jmp     .ret
1693
 
1694
;---------------------------------------------------------------------
1695
; Truncates inode to said size.
1696
; Input:        eax = inode ID.
1697
;               ecx = size to truncate to.
1698
;               ebp = pointer to EXTFS.
1699
; Output:       eax = error code.
1700
;---------------------------------------------------------------------
1701
ext2_inode_truncate:
1702
        push    ebx ecx edx esi edi
1703
 
1704
        ; Save the inode.
1705
        push    eax
1706
 
1707
        ; Read the inode.
1708
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1709
        call    ext2_inode_read
1710
        test    eax, eax
1711
        jnz     .error
1712
 
1713
        mov     eax, [ebx + EXT2_INODE_STRUC.i_size]
1714
        cmp     ecx, eax
1715
        jge     .success
1716
 
1717
        ; Save the size of the inode.
1718
        push    eax
1719
 
1720
        ; ECX contains the size we've to truncate.
1721
        sub     ecx, eax
1722
        not     ecx
1723
        inc     ecx
1724
        xor     edx, edx
1725
        div     [ebp + EXTFS.block_size]
1726
 
1727
        test    edx, edx
1728
        jz      .start_aligned
1729
 
1730
        ; Start isn't aligned, so deal with the non-aligned bytes.
1731
        mov     esi, edx
1732
 
1733
        cmp     esi, ecx
1734
        jbe     @F
1735
 
1736
        ; If the size to truncate is smaller than the un-aligned bytes
1737
        ; we're going to have to mark neccessary bytes from the EOF
1738
        ; as 0.
1739
        push    eax
1740
        call    ext2_inode_read_entry
1741
        test    eax, eax
1742
        pop     eax
1743
        jnz     .error_inode_size
1744
 
1745
        mov     edi, [ebp + EXTFS.ext2_save_block]
1746
        sub     edx, ecx
1747
        add     edi, edx
1748
 
1749
        push    ecx eax
1750
        xor     eax, eax
1751
        rep stosb
1752
        pop     eax ecx
1753
 
1754
        call    ext2_inode_write_entry
1755
        test    eax, eax
1756
        jnz     .error_inode_size
1757
 
1758
        sub     [esp], ecx
1759
        jmp     .write_inode
1760
 
1761
    @@:
1762
        ; Since ECX is greater than or equal to the bytes here un-aligned
1763
        ; just free the block.
1764
        call    ext2_inode_free_entry
1765
 
1766
        sub     [esp], esi
1767
        sub     ecx, esi
1768
        jz      .write_inode
1769
 
1770
    .start_aligned:
1771
        cmp     ecx, [ebp + EXTFS.block_size]
1772
        jb      @F
1773
 
1774
        mov     eax, [esp]
1775
        xor     edx, edx
1776
        div     [ebp + EXTFS.block_size]
1777
        dec     eax
1778
 
1779
        call    ext2_inode_free_entry
1780
 
1781
        test    eax, eax
1782
        jnz     .error_inode_size
1783
 
1784
        mov     eax, [ebp + EXTFS.block_size]
1785
        sub     ecx, eax
1786
        sub     [esp], eax
1787
        jmp     .start_aligned
1788
 
1789
    ; Handle the remaining bytes.
1790
    @@:
1791
        test    ecx, ecx
1792
        jz      .write_inode
1793
 
1794
        mov     eax, [esp]
1795
        xor     edx, edx
1796
        div     [ebp + EXTFS.block_size]
1797
        dec     eax
1798
 
1799
        push    eax
1800
        call    ext2_inode_read_entry
1801
        test    eax, eax
1802
        pop     eax
1803
        jnz     .error_inode_size
1804
 
1805
        mov     edi, [ebp + EXTFS.ext2_save_block]
1806
        mov     edx, [ebp + EXTFS.block_size]
1807
        sub     edx, ecx
1808
        add     edi, edx
1809
 
1810
        push    ecx eax
1811
        xor     eax, eax
1812
        rep stosb
1813
        pop     eax ecx
1814
 
1815
        call    ext2_inode_write_entry
1816
        test    eax, eax
1817
        jnz     .error_inode_size
1818
 
1819
        sub     [esp], ecx
1820
 
1821
    .write_inode:
1822
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1823
        pop     eax
1824
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1825
        mov     eax, [esp]
1826
        call    ext2_inode_write
1827
 
1828
        test    eax, eax
1829
        jnz     .error
1830
 
1831
    .success:
1832
        xor     eax, eax
1833
 
1834
    .ret:
1835
        add     esp, 4
1836
 
1837
        pop     edi esi edx ecx ebx
1838
        ret
1839
 
1840
    .error_inode_size:
1841
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1842
        pop     eax
1843
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1844
        mov     eax, [esp]
1845
        call    ext2_inode_write
1846
 
1847
    .error:
1848
        xor     eax, eax
1849
        not     eax
1850
        jmp     .ret