Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3935 shikhin 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
; KSOC_EXT2_WRITE_END_TODO: clean this up.
11
;---------------------------------------------------------------------
12
; Receives block number from extent-based inode.
13
; Input:        ecx = number of block in inode
14
;               esi = address of extent header
15
;               ebp = pointer to EXTFS
16
; Output:       ecx = address of next block, if successful
17
;               eax = error code (0 implies no error)
18
;---------------------------------------------------------------------
19
ext4_block_recursive_search:
20
        cmp     word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
21
        jne     .fail
22
 
23
        movzx   ebx, [esi + EXT4_EXTENT_HEADER.eh_entries]
24
        add     esi, sizeof.EXT4_EXTENT_HEADER
25
        cmp     word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0
26
        je      .leaf_block     ;листовой ли это блок?
27
 
28
        ;не листовой блок, а индексный ; eax - ext4_extent_idx
29
        test    ebx, ebx
30
        jz      .fail               ;пустой индексный блок -> ошибка
31
 
32
        ;цикл по индексам экстентов
33
    @@:
34
        cmp     ebx, 1              ;у индексов не хранится длина,
35
        je      .end_search_index   ;поэтому, если остался последний - то это нужный
36
 
37
        cmp     ecx, [esi + EXT4_EXTENT_IDX.ei_block]
38
        jb      .fail
39
 
40
        cmp     ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
41
        jb      .end_search_index ;следующий дальше - значит текущий, то что нам нужен
42
 
43
        add     esi, sizeof.EXT4_EXTENT_IDX
44
        dec     ebx
45
        jmp     @B
46
 
47
    .end_search_index:
48
        ;ebp указывает на нужный extent_idx, считываем следующий блок
49
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
50
        mov     eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo]
51
        call    ext2_block_read
52
        test    eax, eax
53
        jnz     .fail
54
        mov     esi, ebx
55
        jmp     ext4_block_recursive_search ;рекурсивно прыгаем в начало
56
 
57
    .leaf_block:    ;листовой блок esi - ext4_extent
58
        ;цикл по экстентам
59
    @@:
60
        test    ebx, ebx
61
        jz      .fail       ;ни один узел не подошел - ошибка
62
 
63
        mov     edx, [esi + EXT4_EXTENT.ee_block]
64
        cmp     ecx, edx
65
        jb      .fail       ;если меньше, значит он был в предыдущих блоках -> ошибка
66
 
67
        movzx   edi, [esi + EXT4_EXTENT.ee_len]
68
        add     edx, edi
69
        cmp     ecx, edx
70
        jb      .end_search_extent     ;нашли нужный блок
71
 
72
        add     esi, sizeof.EXT4_EXTENT
73
        dec     ebx
74
        jmp     @B
75
 
76
    .end_search_extent:
77
        mov     edx, [esi + EXT4_EXTENT.ee_start_lo]
78
        sub     ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
79
        add     ecx, edx
80
        xor     eax, eax
81
        ret
82
 
83
    .fail:
84
        mov     eax, ERROR_FS_FAIL
85
        ret
86
 
87
;---------------------------------------------------------------------
88
; Sets block ID for indirect-addressing inode.
89
; Input:        ecx = index of block in inode
90
;               edi = block ID to set to
91
;               esi = address of inode
92
;               ebp = pointer to EXTFS.
93
; Output:       eax = error code (0 implies no error)
94
;---------------------------------------------------------------------
95
ext2_set_inode_block:
96
        push    ebx ecx edx
97
 
98
        ; 0 to 11: direct blocks.
99
        cmp     ecx, 12
100
        jb      .direct_block
101
 
102
        ; Indirect blocks
103
        sub     ecx, 12
104
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
105
        jb      .indirect_block
106
 
107
        ; Double indirect blocks.
108
        sub     ecx, [ebp + EXTFS.count_pointer_in_block]
109
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
110
        jb      .double_indirect_block
111
 
112
        ; Triple indirect blocks.
113
        sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
114
 
115
        ; Get triply-indirect block in temp_block.
116
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
117
        test    eax, eax
118
        jnz     @F
119
 
120
        ; TODO: fix to have correct preference.
121
        mov     eax, EXT2_ROOT_INO
122
        call    ext2_block_calloc
123
        test    eax, eax
124
        jnz     .fail_alloc
125
 
126
        mov     [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx
127
        mov     eax, ebx
128
 
129
    @@:
130
        push    eax
131
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
132
        call    ext2_block_read
133
        test    eax, eax
134
        jnz     .fail_alloc_4
135
 
136
        ; Get index in triply-indirect block.
137
        xor     edx, edx
138
        mov     eax, ecx
139
        div     [ebp + EXTFS.count_pointer_in_block_square]
140
 
141
        ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
142
        lea     ecx, [ebx + eax*4]
143
        mov     eax, [ebx + eax*4]
144
        test    eax, eax
145
        jnz     @F
146
 
147
        mov     eax, EXT2_ROOT_INO
148
        call    ext2_block_calloc
149
        test    eax, eax
150
        jnz     .fail_alloc_4
151
 
152
        mov     [ecx], ebx
153
 
154
        mov     eax, [esp]
155
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
156
        call    ext2_block_write
157
        test    eax, eax
158
        jnz     .fail_alloc_4
159
 
160
        mov     eax, [ecx]
161
    @@:
162
        mov     [esp], eax
163
        call    ext2_block_read
164
        test    eax, eax
165
        jnz     .fail_alloc_4
166
 
167
        mov     eax, edx
168
        jmp     @F
169
 
170
    .double_indirect_block:
171
        ; Get doubly-indirect block.
172
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
173
        test    eax, eax
174
        jnz     .double_indirect_present
175
 
176
        ; TODO: fix to have correct preference.
177
        mov     eax, EXT2_ROOT_INO
178
        call    ext2_block_calloc
179
        test    eax, eax
180
        jnz     .fail_alloc
181
 
182
        mov     [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx
183
        mov     eax, ebx
184
 
185
    .double_indirect_present:
186
        ; Save block we're at.
187
        push    eax
188
 
189
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
190
        call    ext2_block_read
191
        test    eax, eax
192
        jnz     .fail_alloc_4
193
 
194
        mov     eax, ecx
195
    @@:
196
        xor     edx, edx
197
        div     [ebp + EXTFS.count_pointer_in_block]
198
 
199
        ; eax: index in doubly-indirect block, edx: index in indirect block.
200
        lea     ecx, [ebx + edx*4]
201
        push    ecx
202
 
203
        lea     ecx, [ebx + eax*4]
204
        cmp     dword[ecx], 0
205
        jne     @F
206
 
207
        ; TODO: fix to have correct preference.
208
        mov     eax, EXT2_ROOT_INO
209
        call    ext2_block_calloc
210
        test    eax, eax
211
        jnz     .fail_alloc_8
212
 
213
        mov     [ecx], ebx
214
 
215
        mov     eax, [esp + 4]
216
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
217
        call    ext2_block_write
218
        test    eax, eax
219
        jnz     .fail_alloc_8
220
 
221
    @@:
222
        mov     eax, [ecx]
223
        push    eax
224
        call    ext2_block_read
225
        test    eax, eax
226
        jnz     .fail_alloc_12
227
 
228
        pop     eax
229
        pop     ecx
230
        mov     [ecx], edi
231
        call    ext2_block_write
232
 
233
        add     esp, 4
234
        jmp     .return
235
 
236
    .indirect_block:
237
        ; Get index of indirect block.
238
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
239
        test    eax, eax
240
        jnz     @F
241
 
242
        ; TODO: fix to have correct preference.
243
        mov     eax, EXT2_ROOT_INO
244
        call    ext2_block_calloc
245
        test    eax, eax
246
        jnz     .fail_alloc
247
 
248
        mov     [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx
249
        mov     eax, ebx
250
 
251
    @@:
252
        push    eax
253
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
254
        call    ext2_block_read
255
        test    eax, eax
256
        jnz     .fail_alloc_4
257
 
258
        ; Get the block ID.
259
        mov     [ebx + ecx*4], edi
260
        pop     eax
261
        call    ext2_block_write
262
        jmp     .return
263
 
264
    .direct_block:
265
        mov     [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi
266
        xor     eax, eax
267
 
268
    .return:
269
        pop     edx ecx ebx
270
        ret
271
 
272
    .fail_alloc:
273
        xor     eax, eax
274
        not     eax
275
        jmp     .return
276
 
277
    .fail_alloc_12:
278
        add     esp, 4
279
    .fail_alloc_8:
280
        add     esp, 4
281
    .fail_alloc_4:
282
        add     esp, 4
283
        jmp     .fail_alloc
284
 
285
;---------------------------------------------------------------------
286
; Receives block ID from indirect-addressing inode.
287
; Input:        ecx = index of block in inode
288
;               esi = address of inode
289
;               ebp = pointer to EXTFS
290
; Output:       ecx = block ID, if successful
291
;               eax = error code (0 implies no error)
292
;---------------------------------------------------------------------
293
ext2_get_inode_block:
294
        ; If inode is extent-based, use ext4_block_recursive_search.
295
        test    [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
296
        jz      @F
297
 
298
        pushad
299
 
300
        ; Get extent header in EBP.
301
        add     esi, EXT2_INODE_STRUC.i_block
302
        call    ext4_block_recursive_search
303
        mov     PUSHAD_ECX, ecx
304
        mov     PUSHAD_EAX, eax
305
 
306
        popad
307
        ret
308
 
309
    @@:
310
        ; 0 to 11: direct blocks.
311
        cmp     ecx, 12
312
        jb      .get_direct_block
313
 
314
        ; Indirect blocks
315
        sub     ecx, 12
316
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
317
        jb      .get_indirect_block
318
 
319
        ; Double indirect blocks.
320
        sub     ecx, [ebp + EXTFS.count_pointer_in_block]
321
        cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
322
        jb      .get_double_indirect_block
323
 
324
        ; Triple indirect blocks.
325
        sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
326
        push    edx ebx
327
 
328
        ; Get triply-indirect block in temp_block.
329
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
330
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
331
        call    ext2_block_read
332
        test    eax, eax
333
        jnz     .fail
334
 
335
        ; Get index in triply-indirect block.
336
        xor     edx, edx
337
        mov     eax, ecx
338
        div     [ebp + EXTFS.count_pointer_in_block_square]
339
 
340
        ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
341
        mov     eax, [ebx + eax*4]
342
        call    ext2_block_read
343
        test    eax, eax
344
        jnz     .fail
345
 
346
        mov     eax, edx
347
        jmp     @F
348
 
349
    .get_double_indirect_block:
350
        push    edx ebx
351
 
352
        ; Get doubly-indirect block.
353
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
354
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
355
        call    ext2_block_read
356
        test    eax, eax
357
        jnz     .fail
358
 
359
        mov     eax, ecx
360
    @@:
361
        xor     edx, edx
362
        div     [ebp + EXTFS.count_pointer_in_block]
363
 
364
        ; eax: index in doubly-indirect block, edx: index in indirect block.
365
        mov     eax, [ebx + eax*4]
366
 
367
        call    ext2_block_read
368
        test    eax, eax
369
        jnz     .fail
370
 
371
        mov     ecx, [ebx + edx*4]
372
    .fail:
373
        pop     ebx edx
374
 
375
        ret
376
 
377
    .get_indirect_block:
378
        push    ebx
379
 
380
        ; Get index of indirect block.
381
        mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
382
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
383
        call    ext2_block_read
384
        test    eax, eax
385
        jnz     @F
386
 
387
        ; Get the block ID.
388
        mov     ecx, [ebx + ecx*4]
389
    @@:
390
        pop     ebx
391
 
392
        ret
393
 
394
    .get_direct_block:
395
        mov     ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
396
        xor     eax, eax
397
 
398
        ret
399
 
400
;---------------------------------------------------------------------
401
; Get block containing inode.
402
; Input:        eax = inode number.
403
;               ebp = pointer to EXTFS.
404
; Output:       ebx = block (hard disk) containing inode.
405
;               edx = index inside block.
406
;               eax = error code (0 implies no error)
407
;---------------------------------------------------------------------
408
ext2_read_block_of_inode:
409
        pushad
410
 
411
        dec     eax
412
        xor     edx, edx
413
 
414
        ; EAX = block group.
415
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
416
 
417
        push    edx                             ; Index in group.
418
 
419
        mov     edx, 32
420
        mul     edx                             ; Get index of descriptor in global_desc_table.
421
 
422
        ; eax: inode group offset relative to global descriptor table start
423
        ; Find the block this block descriptor is in.
424
        div     [ebp + EXTFS.block_size]
425
        add     eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
426
        inc     eax
427
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
428
        call    ext2_block_read
429
        test    eax, eax
430
        jnz     .return
431
 
432
        add     ebx, edx                        ; edx: local index of descriptor inside block
433
        mov     eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]   ; Block number of inode table - in ext2 terms.
434
        mov     ecx, [ebp + EXTFS.log_block_size]
435
        shl     eax, cl
436
 
437
        ; eax: points to inode table on HDD.
438
        mov     esi, eax
439
 
440
        ; Add local address of inode.
441
        pop     eax
442
        mov     ecx, [ebp + EXTFS.inode_size]
443
        mul     ecx                             ; (index * inode_size)
444
 
445
        mov     ebp, 512
446
        div     ebp                             ; Divide by hard disk block size.
447
 
448
        add     eax, esi                        ; Found block to read.
449
        mov     ebx, eax                        ; Get it inside ebx.
450
 
451
        xor     eax, eax
452
    .return:
453
        mov     PUSHAD_EAX, eax
454
        mov     PUSHAD_EBX, ebx
455
        mov     PUSHAD_EDX, edx
456
 
457
        popad
458
        ret
459
 
460
;---------------------------------------------------------------------
461
; Sets content of inode by number.
462
; Input:        eax = inode number.
463
;               ebx = address from where to write inode content.
464
;               ebp = pointer to EXTFS.
465
; Output:       eax = error code (0 implies no error)
466
;---------------------------------------------------------------------
467
ext2_inode_write:
468
        push    edx edi esi ecx ebx
469
        mov     esi, ebx
470
 
471
        ; Ext2 actually stores time of modification of inode in ctime.
472
        lea     edi, [ebx + EXT2_INODE_STRUC.i_ctime]
473
        call    current_unix_time
474
 
475
        ; Get block where inode is situated.
476
        call    ext2_read_block_of_inode
477
        test    eax, eax
478
        jnz     .error
479
 
480
        mov     eax, ebx                        ; Get block into EAX.
481
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
482
 
483
        mov     ecx, eax                        ; Save block.
484
        call    fs_read32_sys
485
        test    eax, eax
486
        jz      @F
487
 
488
    .error:
489
        mov     eax, ERROR_DEVICE
490
        jmp     .return
491
 
492
    @@:
493
        mov     eax, ecx
494
        mov     ecx, [ebp + EXTFS.inode_size]
495
        mov     edi, edx                        ; The index into the block.
496
        add     edi, ebx
497
        rep movsb
498
 
499
        ; Write the block.
500
        call    fs_write32_sys
501
 
502
    .return:
503
        pop     ebx ecx esi edi edx
504
        ret
505
 
506
;---------------------------------------------------------------------
507
; Get content of inode by number.
508
; Input:        eax = inode number.
509
;               ebx = address where to store inode content.
510
;               ebp = pointer to EXTFS.
511
; Output:       eax = error code (0 implies no error)
512
;---------------------------------------------------------------------
513
ext2_inode_read:
514
        push    edx edi esi ecx ebx
515
        mov     edi, ebx
516
 
517
        ; Get block where inode is situated.
518
        call    ext2_read_block_of_inode
519
        test    eax, eax
520
        jnz     .error
521
 
522
        mov     eax, ebx                        ; Get block into EAX.
523
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
524
        call    fs_read32_sys
525
        test    eax, eax
526
        jz      @F
527
 
528
    .error:
529
        mov     eax, ERROR_DEVICE
530
        jmp     .return
531
 
532
    @@:
533
        mov     ecx, [ebp + EXTFS.inode_size]
534
        mov     esi, edx                        ; The index into the inode.
535
        add     esi, ebx
536
        rep movsb
537
 
538
        xor     eax, eax
539
    .return:
540
        pop     ebx ecx esi edi edx
541
        ret
542
 
543
;---------------------------------------------------------------------
544
; Seek inode from the path.
545
; Input:        esi + [esp + 4] = name.
546
;               ebp = pointer to EXTFS.
547
; Output:       eax = error code (0 implies no error)
548
;               esi = inode number.
549
;                dl = first byte of file/folder name.
550
;                     [ext2_data.ext2_save_inode] stores the inode.
551
;---------------------------------------------------------------------
552
ext2_inode_find:
553
        mov     edx, [ebp + EXTFS.root_inode]
554
 
555
        ; Check for empty root.
556
        cmp     [edx + EXT2_INODE_STRUC.i_blocks], 0
557
        je      .error_empty_root
558
 
559
        ; Check for root.
560
        cmp     byte[esi], 0
561
        jne     .next_path_part
562
 
563
        push    edi ecx
564
        mov     esi, [ebp + EXTFS.root_inode]
565
        mov     edi, [ebp + EXTFS.ext2_save_inode]
566
        mov     ecx, [ebp + EXTFS.inode_size]
567
        rep movsb
568
        pop     ecx edi
569
 
570
        xor     eax, eax
571
        xor     dl, dl
572
        mov     esi, EXT2_ROOT_INO
573
        ret     4
574
 
575
    .next_path_part:
576
        push    [edx + EXT2_INODE_STRUC.i_blocks]
577
        xor     ecx, ecx
578
 
579
    .folder_block_cycle:
580
        push    ecx
581
        xchg    esi, edx
582
        call    ext2_get_inode_block
583
        xchg    esi, edx
584
        test    eax, eax
585
        jnz     .error_get_inode_block
586
 
587
        mov     eax, ecx
588
        mov     ebx, [ebp + EXTFS.ext2_save_block]              ; Get directory records from directory.
589
        call    ext2_block_read
590
        test    eax, eax
591
        jnz     .error_get_block
592
 
593
        push    esi
594
        push    edx
595
        call    ext2_block_find_parent
596
        pop     edx
597
        pop     edi ecx
598
 
599
        cmp     edi, esi                                        ; Did something match?
600
        je      .next_folder_block                              ; No, move to next block.
601
 
602
        cmp     byte [esi], 0                                   ; Reached the "end" of path successfully.
603
        jnz     @F
604
        cmp     dword[esp + 8], 0
605
        je      .get_inode_ret
606
        mov     esi, [esp + 8]
607
        mov     dword[esp + 8], 0
608
 
609
    @@:
610
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]
611
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
612
        call    ext2_inode_read
613
        test    eax, eax
614
        jnz     .error_get_inode
615
 
616
        movzx   eax, [ebx + EXT2_INODE_STRUC.i_mode]
617
        and     eax, EXT2_S_IFMT                                ; Get the mask.
618
        cmp     eax, EXT2_S_IFDIR
619
        jne     .not_found                                      ; Matched till part, but directory entry we got doesn't point to folder.
620
 
621
        pop     ecx                                             ; Stack top contains number of blocks.
622
        mov     edx, ebx
623
        jmp     .next_path_part
624
 
625
    .next_folder_block:
626
        ; Next block in current folder.
627
        pop     eax                                             ; Get blocks counter.
628
        sub     eax, [ebp + EXTFS.count_block_in_block]
629
        jle     .not_found
630
 
631
        push    eax
632
        inc     ecx
633
        jmp     .folder_block_cycle
634
 
635
    .not_found:
636
        mov     eax, ERROR_FILE_NOT_FOUND
637
        ret     4
638
 
639
    .get_inode_ret:
640
        pop     ecx                                             ; Stack top contains number of blocks.
641
 
642
        mov     dl, [ebx + EXT2_DIR_STRUC.name]                 ; First character of file-name.
643
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]
644
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
645
        mov     esi, eax
646
 
647
        ; If we can't get the inode, eax contains the error.
648
        call    ext2_inode_read
649
        ret     4
650
 
651
    .error_get_inode_block:
652
    .error_get_block:
653
        pop     ecx
654
    .error_get_inode:
655
        pop     ebx
656
    .error_empty_root:
657
        mov     eax, ERROR_FS_FAIL
658
        ret     4
659
 
660
;---------------------------------------------------------------------
661
; Seeks parent inode from path.
662
; Input:        esi = path.
663
;               ebp = pointer to EXTFS.
664
; Output:       eax = error code.
665
;               esi = inode.
666
;               edi = pointer to file name.
667
;---------------------------------------------------------------------
668
ext2_inode_find_parent:
669
        push    esi
670
        xor     edi, edi
671
 
672
    .loop:
673
        cmp     byte[esi], '/'
674
        jne     @F
675
 
676
        mov     edi, esi
677
        inc     esi
678
        jmp     .loop
679
 
680
    @@:
681
        inc     esi
682
        cmp     byte[esi - 1], 0
683
        jne     .loop
684
 
685
        ; If it was just a filename (without any additional directories),
686
        ; use the last byte as "parent path".
687
        cmp     edi, 0
688
        jne     @F
689
 
690
        pop     edi
691
        dec     esi
692
        jmp     .get_inode
693
 
694
        ; It had some additional directories, so handle it that way.
695
    @@:
696
        mov     byte[edi], 0
697
        inc     edi
698
        pop     esi
699
 
700
    .get_inode:
701
        push    ebx edx
702
        stdcall ext2_inode_find, 0
703
        pop     edx ebx
704
 
705
    .return:
706
        ret
707
 
708
;---------------------------------------------------------------------
709
; Link an inode.
710
; Input:        eax = inode on which to link.
711
;               ebx = inode to link.
712
;                dl = file type.
713
;               esi = name.
714
;               ebp = pointer to EXTFS.
715
; Output:       eax = error code.
716
;---------------------------------------------------------------------
717
ext2_inode_link:
718
        push    eax
719
        push    esi edi ebx ecx edx
720
 
721
        ; Get string length, and then directory entry structure size.
722
        call    strlen
723
        add     ecx, 8
724
 
725
        push    esi ebx ecx
726
 
727
        xor     ecx, ecx
728
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
729
        mov     ebx, esi
730
 
731
        call    ext2_inode_read
732
        test    eax, eax
733
        jnz     .error_inode_read
734
 
735
        ; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)).
736
        ; Note that i_blocks contains number of reserved 512B blocks, which is why we've to
737
        ; find out the ext2 blocks.
738
        mov     eax, 2
739
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
740
        shl     eax, cl
741
        mov     ecx, eax
742
 
743
        mov     eax, [esi + EXT2_INODE_STRUC.i_blocks]
744
        xor     edx, edx
745
 
746
        div     ecx
747
 
748
        ; EAX is the maximum index inside i_block we can go.
749
        push    eax
750
        push    dword 0
751
 
752
        ; ECX contains the "block inside i_block" index.
753
        xor     ecx, ecx
754
    @@:
755
        call    ext2_get_inode_block
756
        test    eax, eax
757
        jnz     .error_get_inode_block
758
        test    ecx, ecx
759
        jz      .alloc_block        ; We've got no block here, so allocate one.
760
 
761
        push    ecx                 ; Save block number.
762
 
763
        mov     eax, ecx
764
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
765
        call    ext2_block_read
766
        test    eax, eax
767
        jnz     .error_block_read
768
 
769
        ; Try to find free space in current block.
770
        mov     ecx, [esp + 8]
771
        call    ext2_block_find_fspace
772
        test    eax, eax
773
        jz      .found
774
 
775
        cmp     eax, 0x00000001
776
        jne     .next_iter
777
 
778
        ; This block wasn't linking to the next block, so fix that, and use the next one.
779
        ; Write the block.
780
        pop     eax
781
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
782
        call    ext2_block_write
783
        test    eax, eax
784
        jnz     .error_get_inode_block
785
 
786
        inc     dword [esp]
787
        mov     ecx, [esp]
788
        call    ext2_get_inode_block
789
        test    eax, eax
790
        jnz     .error_get_inode_block
791
 
792
        test    ecx, ecx
793
        jz      .alloc_block
794
 
795
        ; If there was a block there, prepare it for our use!
796
        push    ecx
797
        jmp     .prepare_block
798
 
799
    .next_iter:
800
        add     esp, 4
801
 
802
        inc     dword [esp]
803
        mov     ecx, [esp]
804
        cmp     ecx, [esp + 4]
805
        jbe     @B
806
 
807
    .alloc_block:
808
        mov     eax, [esp + 12]     ; Get inode ID of what we're linking.
809
        call    ext2_block_calloc
810
        test    eax, eax
811
        jnz     .error_get_inode_block
812
 
813
        mov     ecx, [esp]          ; Get the index of it inside the inode.
814
        mov     edi, ebx            ; And what to set to.
815
        call    ext2_set_inode_block
816
        test    eax, eax
817
        jnz     .error_get_inode_block
818
 
819
        ; Update i_size.
820
        mov     eax, [ebp + EXTFS.block_size]
821
        add     [esi + EXT2_INODE_STRUC.i_size], eax
822
 
823
        ; Update i_blocks.
824
        mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
825
        mov     eax, 2
826
        shl     eax, cl
827
        add     [esi + EXT2_INODE_STRUC.i_blocks], eax
828
 
829
        ; Write the inode.
830
        mov     eax, [esp + 40]
831
        mov     ebx, esi
832
        call    ext2_inode_write
833
        test    eax, eax
834
        jnz     .error_get_inode_block
835
 
836
        push    edi                 ; Save the block we just allocated.
837
 
838
    ; If we've allocated/using-old-block outside of loop, prepare it.
839
    .prepare_block:
840
        mov     eax, [esp]
841
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
842
        call    ext2_block_read
843
        test    eax, eax
844
        jnz     .error_block_read
845
 
846
        mov     edi, ebx
847
        mov     eax, [ebp + EXTFS.block_size]
848
        mov     [edi + EXT2_DIR_STRUC.rec_len], ax
849
 
850
    .found:
851
        pop     edx
852
        add     esp, 8
853
        pop     ecx ebx esi
854
 
855
        push    ebx
856
        mov     [edi], ebx          ; Save inode.
857
 
858
        mov     eax, [esp + 4]      ; Get EDX off the stack -- contains the file_type.
859
        cmp     [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV
860
        je      .name
861
 
862
        ; Set the file-type.
863
        mov     [edi + EXT2_DIR_STRUC.file_type], al
864
 
865
    .name:
866
        ; Save name.
867
        sub     ecx, 8
868
        mov     [edi + EXT2_DIR_STRUC.name_len], cl
869
        add     edi, 8
870
        rep movsb
871
 
872
        ; Write block.
873
        mov     eax, edx
874
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
875
        call    ext2_block_write
876
        test    eax, eax
877
        jnz     .error_block_write
878
 
879
        mov     eax, [esp]
880
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
881
        call    ext2_inode_read
882
        test    eax, eax
883
        jnz     .error_block_write
884
 
885
        pop     eax
886
        inc     [ebx + EXT2_INODE_STRUC.i_links_count]
887
        call    ext2_inode_write
888
        test    eax, eax
889
        jnz     .error
890
 
891
        xor     eax, eax
892
    .ret:
893
        pop     edx ecx ebx edi esi
894
        add     esp, 4
895
        ret
896
 
897
    .error_block_read:
898
        add     esp, 4
899
    .error_get_inode_block:
900
        add     esp, 8
901
    .error_inode_read:
902
        add     esp, 8
903
    .error_block_write:
904
        add     esp, 4
905
    .error:
906
        xor     eax, eax
907
        not     eax
908
        jmp     .ret
909
 
910
;---------------------------------------------------------------------
911
; Unlink an inode.
912
; Input:        eax = inode from which to unlink.
913
;               ebx = inode to unlink.
914
;               ebp = pointer to EXTFS.
915
; Output:       eax = number of links to inode, after unlinking (0xFFFFFFFF implies error)
916
;---------------------------------------------------------------------
917
ext2_inode_unlink:
918
        push    ebx ecx edx esi edi
919
 
920
        push    ebx
921
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
922
        call    ext2_inode_read
923
 
924
        test    eax, eax
925
        jnz     .fail_get_inode
926
 
927
        ; The index into the inode block data.
928
        push    dword 0
929
        mov     esi, [ebp + EXTFS.ext2_temp_inode]
930
 
931
    .loop:
932
        mov     ecx, [esp]
933
        call    ext2_get_inode_block
934
 
935
        test    eax, eax
936
        jnz     .fail_loop
937
        test    ecx, ecx
938
        jz      .fail_loop
939
 
940
        mov     eax, ecx
941
        mov     edi, eax
942
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
943
        call    ext2_block_read
944
        test    eax, eax
945
        jnz     .fail_loop
946
 
947
    ; edi -> block.
948
    .first_dir_entry:
949
        mov     eax, [esp + 4]
950
        cmp     [ebx], eax
951
        jne     @F
952
 
953
        mov     dword[ebx], 0                               ; inode.
954
        mov     word[ebx + 6], 0                            ; name_len + file_type.
955
        jmp     .write_block
956
 
957
    @@:
958
        mov     edx, ebx
959
        add     edx, [ebp + EXTFS.block_size]
960
        push    edx
961
 
962
        mov     edx, ebx
963
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
964
        add     ebx, ecx
965
 
966
    .dir_entry:
967
        cmp     [ebx], eax
968
        jne     @F
969
 
970
        mov     cx, [ebx + EXT2_DIR_STRUC.rec_len]
971
        add     [edx + EXT2_DIR_STRUC.rec_len], cx
972
        add     esp, 4
973
        jmp     .write_block
974
 
975
    @@:
976
        mov     edx, ebx
977
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
978
 
979
        ; If it's a zero length entry, error.
980
        test    ecx, ecx
981
        jz      .fail_inode
982
 
983
        add     ebx, ecx
984
 
985
        cmp     ebx, [esp]
986
        jb      .dir_entry
987
 
988
        add     esp, 4
989
        inc     dword[esp]
990
        jmp     .loop
991
 
992
    .write_block:
993
        mov     eax, edi
994
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
995
        call    ext2_block_write
996
        test    eax, eax
997
        jnz     .fail_loop
998
 
999
        add     esp, 4
1000
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1001
        mov     eax, [esp]
1002
        call    ext2_inode_read
1003
        test    eax, eax
1004
        jnz     .fail_get_inode
1005
 
1006
        dec     word[ebx + EXT2_INODE_STRUC.i_links_count]
1007
        movzx   eax, word[ebx + EXT2_INODE_STRUC.i_links_count]
1008
        push    eax
1009
 
1010
        mov     eax, [esp + 4]
1011
        call    ext2_inode_write
1012
        test    eax, eax
1013
        jnz     .fail_loop
1014
 
1015
        pop     eax
1016
        add     esp, 4
1017
    .return:
1018
        pop     edi esi edx ecx ebx
1019
        ret
1020
 
1021
    .fail_inode:
1022
        add     esp, 4
1023
 
1024
    .fail_loop:
1025
        add     esp, 4
1026
 
1027
    .fail_get_inode:
1028
        add     esp, 4
1029
 
1030
    .fail:
1031
        xor     eax, eax
1032
        not     eax
1033
        jmp     .return
1034
 
1035
;---------------------------------------------------------------------
1036
; Checks if a directory is empty.
1037
; Input:        ebx = inode to check.
1038
;               ebp = pointer to EXTFS.
1039
;               [EXTFS.ext2_save_inode] = points to saved inode.
1040
; Output:       eax = 0 signifies empty directory.
1041
;---------------------------------------------------------------------
1042
ext2_dir_empty:
1043
        push    ebx ecx edx
1044
 
1045
        ; The index into the inode block data.
1046
        push    dword 0
1047
        mov     esi, [ebp + EXTFS.ext2_save_inode]
1048
 
1049
    .loop:
1050
        mov     ecx, [esp]
1051
        call    ext2_get_inode_block
1052
 
1053
        ; Treat a failure as not-empty.
1054
        test    eax, eax
1055
        jnz     .not_empty
1056
        test    ecx, ecx
1057
        jz      .empty
1058
 
1059
        mov     eax, ecx
1060
        mov     ebx, [ebp + EXTFS.ext2_temp_block]
1061
        call    ext2_block_read
1062
        test    eax, eax
1063
        jnz     .not_empty
1064
 
1065
        mov     edx, ebx
1066
        add     edx, [ebp + EXTFS.block_size]
1067
 
1068
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1069
        add     ebx, ecx
1070
 
1071
    .dir_entry:
1072
        ; Process entry.
1073
        cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 1
1074
        jne     @F
1075
 
1076
        cmp     byte[ebx + EXT2_DIR_STRUC.name], '.'
1077
        jne     .not_empty
1078
 
1079
    @@:
1080
        cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 2
1081
        jne     .not_empty
1082
 
1083
        cmp     word[ebx + EXT2_DIR_STRUC.name], '..'
1084
        jne     .not_empty
1085
 
1086
    @@:
1087
        movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
1088
        add     ebx, ecx
1089
 
1090
        cmp     ebx, edx
1091
        jb      .dir_entry
1092
 
1093
        inc     dword[esp]
1094
        jmp     .loop
1095
 
1096
    .empty:
1097
        xor     eax, eax
1098
    .return:
1099
        add     esp, 4
1100
        pop     edx ecx ebx
1101
        ret
1102
 
1103
    .not_empty:
1104
        xor     eax, eax
1105
        not     eax
1106
        jmp     .return
1107
 
1108
;---------------------------------------------------------------------
1109
; Gets the block group's inode bitmap.
1110
; Input:        eax = block group.
1111
; Output:       eax = if zero, error; else, points to block group descriptor.
1112
;               ebx = inode bitmap's block (hard disk).
1113
;---------------------------------------------------------------------
1114
ext2_bg_read_inode_bitmap:
1115
        push    ecx
1116
 
1117
        call    ext2_bg_read_desc
1118
        test    eax, eax
1119
        jz      .fail
1120
 
1121
        mov     ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms.
1122
 
1123
    .return:
1124
        pop     ecx
1125
        ret
1126
 
1127
    .fail:
1128
        xor     eax, eax
1129
        jmp     .return
1130
 
1131
;---------------------------------------------------------------------
1132
; Allocates a inode.
1133
; Input:        eax = inode ID for "preference".
1134
;               ebp = pointer to EXTFS.
1135
; Output:       Inode marked as set in inode group.
1136
;               eax = error code.
1137
;               ebx = inode ID.
1138
;---------------------------------------------------------------------
1139
ext2_inode_alloc:
1140
        push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count]
1141
        push    EXT2_BLOCK_GROUP_DESC.free_inodes_count
1142
        push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1143
 
1144
        lea     ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count]
1145
        push    ebx
1146
 
1147
        push    ext2_bg_read_inode_bitmap
1148
 
1149
        call    ext2_resource_alloc
1150
 
1151
        ; Inode table starts with 1.
1152
        inc     ebx
1153
 
1154
        ret
1155
 
1156
;---------------------------------------------------------------------
1157
; Frees a inode.
1158
; Input:        eax = inode ID.
1159
;               ebp = pointer to EXTFS.
1160
; Output:       inode marked as free in block group.
1161
;               eax = error code.
1162
;---------------------------------------------------------------------
1163
ext2_inode_free:
1164
        push    edi ecx
1165
 
1166
        ; Inode table starts with 1.
1167
        dec     eax
1168
 
1169
        mov     edi, ext2_bg_read_inode_bitmap
1170
        xor     ecx, ecx
1171
        inc     cl
1172
        call    ext2_resource_free
1173
 
1174
        pop     ecx edi
1175
        ret