Subversion Repositories Kolibri OS

Rev

Rev 4891 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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