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 initialization, plus syscall 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
include 'ext2.inc'
11
include 'blocks.asm'
12
include 'inode.asm'
13
include 'resource.asm'
14
 
15
iglobal
16
align 4
17
ext2_user_functions:
18
        dd      ext2_free
19
        dd      (ext2_user_functions_end - ext2_user_functions - 4) / 4
20
        dd      ext2_Read
21
        dd      ext2_ReadFolder
22
        dd      ext2_Rewrite
23
        dd      ext2_Write
24
        dd      ext2_SetFileEnd
25
        dd      ext2_GetFileInfo
26
        dd      ext2_SetFileInfo
27
        dd      0
28
        dd      ext2_Delete
29
        dd      ext2_CreateFolder
30
ext2_user_functions_end:
31
endg
32
 
33
;---------------------------------------------------------------------
34
; Locks up an ext2 partition.
35
; Input:        ebp = pointer to EXTFS.
36
;---------------------------------------------------------------------
37
proc ext2_lock
38
        lea     ecx, [ebp + EXTFS.lock]
39
        jmp     mutex_lock
40
endp
41
 
42
;---------------------------------------------------------------------
43
; Unlocks up an ext2 partition.
44
; Input:        ebp = pointer to EXTFS.
45
;---------------------------------------------------------------------
46
proc ext2_unlock
47
        lea     ecx, [ebp + EXTFS.lock]
48
        jmp     mutex_unlock
49
endp
50
 
51
;---------------------------------------------------------------------
52
; Check if it's a valid ext* superblock.
53
; Input:        ebp:       first three fields of PARTITION structure.
54
;               ebx + 512: points to 512-bytes buffer that can be used for anything.
55
; Output:       eax:       clear if can't create partition; set to EXTFS otherwise.
56
;---------------------------------------------------------------------
57
proc ext2_create_partition
58
        push    ebx
59
 
60
        mov     eax, 2                          ; Superblock starts at 1024-bytes.
61
        add     ebx, 512                        ; Get pointer to fs-specific buffer.
62
        call    fs_read32_sys
63
        test    eax, eax
64
        jnz     .fail
65
 
66
        ; Allowed 1KiB, 2KiB, 4KiB, 8KiB.
67
        cmp     [ebx + EXT2_SB_STRUC.log_block_size], 3
68
        ja      .fail
69
 
70
        cmp     [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC
71
        jne     .fail
72
 
73
        cmp     [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS
74
        jne     .fail
75
 
76
        ; Can't have no inodes per group.
77
        cmp     [ebx + EXT2_SB_STRUC.inodes_per_group], 0
78
        je      .fail
79
 
80
        ; If incompatible features required, unusable superblock.
81
        mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
82
        test    eax, not EXT4_FEATURE_INCOMPAT_SUPP
83
        jz      .setup
84
 
85
    .fail:
86
        ; Not a (valid/usable) EXT2 superblock.
87
        pop     ebx
88
        xor     eax, eax
89
        ret
90
 
91
    .setup:
92
        movi    eax, sizeof.EXTFS
93
        call    malloc
94
        test    eax, eax
95
        jz      ext2_create_partition.fail
96
 
97
        ; Store the first sector field.
98
        mov     ecx, dword[ebp + PARTITION.FirstSector]
99
        mov     dword[eax + EXTFS.FirstSector], ecx
100
        mov     ecx, dword [ebp + PARTITION.FirstSector+4]
101
        mov     dword [eax + EXTFS.FirstSector+4], ecx
102
 
103
        ; The length field.
104
        mov     ecx, dword[ebp + PARTITION.Length]
105
        mov     dword[eax + EXTFS.Length], ecx
106
        mov     ecx, dword[ebp + PARTITION.Length+4]
107
        mov     dword[eax + EXTFS.Length+4], ecx
108
 
109
        ; The disk field.
110
        mov     ecx, [ebp + PARTITION.Disk]
111
        mov     [eax + EXTFS.Disk], ecx
112
 
113
        mov     [eax + EXTFS.FSUserFunctions], ext2_user_functions
114
 
115
        push    ebp esi edi
116
 
117
        mov     ebp, eax
118
        lea     ecx, [eax + EXTFS.lock]
119
        call    mutex_init
120
 
121
        ; Copy superblock from buffer to reserved memory.
122
        mov     esi, ebx
123
        lea     edi, [ebp + EXTFS.superblock]
124
        mov     ecx, 512/4
125
        rep movsd
126
 
127
        ; Get total groups.
128
        mov     eax, [ebx + EXT2_SB_STRUC.blocks_count]
129
        sub     eax, [ebx + EXT2_SB_STRUC.first_data_block]
130
        dec     eax
131
        xor     edx, edx
132
        div     [ebx + EXT2_SB_STRUC.blocks_per_group]
133
        inc     eax
134
        mov     [ebp + EXTFS.groups_count], eax
135
 
136
        ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB.
137
        mov     ecx, [ebx + EXT2_SB_STRUC.log_block_size]
138
        inc     ecx
139
        mov     [ebp + EXTFS.log_block_size], ecx
140
 
141
        ; 512-byte blocks in ext2 blocks.
142
        mov     eax, 1
143
        shl     eax, cl
144
        mov     [ebp + EXTFS.count_block_in_block], eax
145
 
146
        ; Get block_size/4 (we'll find square later).
147
        shl     eax, 7
148
        mov     [ebp + EXTFS.count_pointer_in_block], eax
149
        mov     edx, eax
150
 
151
        ; Get block size.
152
        shl     eax, 2
153
        mov     [ebp + EXTFS.block_size], eax
154
 
155
        ; Save block size for 2 kernel_alloc calls.
156
        push    eax eax
157
 
158
        mov     eax, edx
159
        mul     edx
160
        mov     [ebp + EXTFS.count_pointer_in_block_square], eax
161
 
162
        ; Have temporary block storage for get_inode procedure, and one for global procedure.
163
        KERNEL_ALLOC [ebp + EXTFS.ext2_save_block], .error
164
        KERNEL_ALLOC [ebp + EXTFS.ext2_temp_block], .error
165
 
166
        mov     [ebp + EXTFS.partition_flags], 0x00000000
167
        mov     eax, [ebx + EXT2_SB_STRUC.feature_ro_compat]
168
        and     eax, not EXT2_FEATURE_RO_COMPAT_SUPP
169
        jnz     .read_only
170
 
171
        mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
172
        and     eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP
173
        jz      @F
174
 
175
    .read_only:
176
        ; Mark as read-only.
177
        or      [ebp + EXTFS.partition_flags], EXT2_RO
178
    @@:
179
        mov     ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
180
        mov     [ebp + EXTFS.blocks_per_group], ecx
181
 
182
        movzx   ecx, word[ebx + EXT2_SB_STRUC.inode_size]
183
        mov     [ebp + EXTFS.inode_size], ecx
184
 
185
        ; Allocate for three inodes (loop would be overkill).
186
        push    ecx ecx ecx
187
 
188
        KERNEL_ALLOC [ebp + EXTFS.ext2_save_inode], .error
189
        KERNEL_ALLOC [ebp + EXTFS.ext2_temp_inode], .error
190
        KERNEL_ALLOC [ebp + EXTFS.root_inode], .error
191
 
192
        ; Read root inode.
193
        mov     ebx, eax
194
        mov     eax, EXT2_ROOT_INO
195
        call    ext2_inode_read
196
 
197
        test    eax, eax
198
        jnz     .error
199
 
200
        mov     eax, ebp                        ; Return pointer to EXTFS.
201
        pop     edi esi ebp ebx
202
        ret
203
 
204
    ; Error in setting up.
205
    .error:
206
        ; Free save block.
207
        KERNEL_FREE [ebp + EXTFS.ext2_save_block], .fail
208
 
209
        ; Temporary block.
210
        KERNEL_FREE [ebp + EXTFS.ext2_temp_block], .fail
211
 
212
        ; All inodes.
213
        KERNEL_FREE [ebp + EXTFS.ext2_save_inode], .fail
214
        KERNEL_FREE [ebp + EXTFS.ext2_temp_inode], .fail
215
        KERNEL_FREE [ebp + EXTFS.root_inode], .fail
216
 
217
        mov     eax, ebp
218
        call    free
219
 
220
        jmp     .fail
221
endp
222
 
223
; FUNCTIONS PROVIDED BY SYSCALLS.
224
 
225
;---------------------------------------------------------------------
226
; Frees up all ext2 structures.
227
; Input:        eax = pointer to EXTFS.
228
;---------------------------------------------------------------------
229
proc ext2_free
230
        push    ebp
231
 
232
        xchg    ebp, eax
233
        stdcall kernel_free, [ebp+EXTFS.ext2_save_block]
234
        stdcall kernel_free, [ebp+EXTFS.ext2_temp_block]
235
        stdcall kernel_free, [ebp+EXTFS.ext2_save_inode]
236
        stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode]
237
        stdcall kernel_free, [ebp+EXTFS.root_inode]
238
 
239
        xchg    ebp, eax
240
        call    free
241
 
242
        pop     ebp
243
        ret
244
endp
245
 
246
;---------------------------------------------------------------------
247
; Read disk folder.
248
; Input:        ebp = pointer to EXTFS structure.
249
;               esi + [esp + 4] = file name.
250
;               ebx = pointer to parameters from sysfunc 70.
251
; Output:       ebx = blocks read (or 0xFFFFFFFF, folder not found)
252
;               eax = error code (0 implies no error)
253
;---------------------------------------------------------------------
254
ext2_ReadFolder:
255
        call    ext2_lock
256
        cmp     byte [esi], 0
257
        jz      .root_folder
258
 
259
        push    ebx
260
        stdcall ext2_inode_find, [esp + 4 + 4]            ; Get inode.
261
        pop     ebx
262
 
263
        mov     esi, [ebp + EXTFS.ext2_save_inode]
264
        test    eax, eax
265
        jnz     .error_ret
266
 
267
        ; If not a directory, then return with error.
268
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
269
        jz      .error_not_found
270
        jmp     @F
271
 
272
    .root_folder:
273
        mov     esi, [ebp + EXTFS.root_inode]
274
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
275
        jz      .error_root
276
 
277
        ; Copy the inode.
278
        mov     edi, [ebp + EXTFS.ext2_save_inode]
279
        mov     ecx, [ebp + EXTFS.inode_size]
280
        shr     ecx, 2
281
 
282
        push    edi
283
        rep movsd
284
        pop     esi
285
 
286
    @@:
287
        cmp     [esi + EXT2_INODE_STRUC.i_size], 0      ; Folder is empty.
288
        je      .error_empty_dir
289
 
290
        mov     edx, [ebx + 16]
291
        push    edx                                     ; Result address [edi + 28].
292
        push    0                                       ; End of the current block in folder [edi + 24]
293
        push    dword[ebx + 12]                         ; Blocks to read [edi + 20]
294
        push    dword[ebx + 4]                          ; The first wanted file [edi + 16]
295
        push    dword[ebx + 8]                          ; Flags [edi + 12]
296
        push    0                                       ; Read files [edi + 8]
297
        push    0                                       ; Files in folder [edi + 4]
298
        push    0                                       ; Number of blocks read in dir (and current block index) [edi]
299
 
300
        ; Fill header with zeroes.
301
        mov     edi, edx
302
        mov     ecx, 32/4
303
        rep stosd
304
 
305
        mov     edi, esp                                ; edi = pointer to local variables.
306
        add     edx, 32                                 ; edx = mem to return.
307
 
308
        xor     ecx, ecx                                ; Get number of first block.
309
        call    ext2_get_inode_block
310
        test    eax, eax
311
        jnz     .error_get_block
312
 
313
        mov     eax, ecx
314
        mov     ebx, [ebp + EXTFS.ext2_save_block]
315
        call    ext2_block_read                          ; Read the block.
316
        test    eax, eax
317
        jnz     .error_get_block
318
 
319
        mov     eax, ebx                                ; esi: current directory record
320
        add     eax, [ebp + EXTFS.block_size]
321
 
322
        mov     [edi + 24], eax
323
 
324
        mov     ecx, [edi + 16]                         ; ecx = first wanted (flags ommited)
325
 
326
    .find_wanted_start:
327
        jecxz   .find_wanted_end
328
 
329
    .find_wanted_cycle:
330
        cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; Don't count unused inode in total files.
331
        jz      @F
332
 
333
        inc     dword [edi + 4]                         ; EXT2 files in folder.
334
        dec     ecx
335
    @@:
336
        movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
337
 
338
        cmp     eax, 12                                 ; Minimum record length.
339
        jb      .error_bad_len
340
        test    eax, 0x3                                ; Record length must be divisible by four.
341
        jnz     .error_bad_len
342
 
343
        sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract "processed record" length directly from inode.
344
        add     ebx, eax                                ; Go to next record.
345
        cmp     ebx, [edi + 24]                         ; If not reached the next block, continue.
346
        jb      .find_wanted_start
347
 
348
        push    .find_wanted_start
349
   .end_block:                                          ; Get the next block.
350
        cmp     [esi + EXT2_INODE_STRUC.i_size], 0
351
        jle     .end_dir
352
 
353
        inc     dword [edi]                             ; Number of blocks read.
354
 
355
        ; Read the next block.
356
        push    ecx
357
        mov     ecx, [edi]
358
        call    ext2_get_inode_block
359
        test    eax, eax
360
        jnz     .error_get_block
361
 
362
        mov     eax, ecx
363
        mov     ebx, [ebp + EXTFS.ext2_save_block]
364
        call    ext2_block_read
365
        test    eax, eax
366
        jnz     .error_get_block
367
        pop     ecx
368
 
369
        mov     eax, ebx
370
        add     eax, [ebp + EXTFS.block_size]
371
        mov     [edi + 24], eax                         ; Update the end of the current block variable.
372
        ret
373
 
374
    .wanted_end:
375
        loop    .find_wanted_cycle                      ; Skip files till we reach wanted one.
376
 
377
    ; First requisite file.
378
    .find_wanted_end:
379
        mov     ecx, [edi + 20]
380
    .wanted_start:                                      ; Look for first_wanted + count.
381
        jecxz   .wanted_end
382
 
383
        cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; if (inode == 0): not used;
384
        jz      .empty_rec
385
 
386
        ; Increment "files in dir" and "read files" count.
387
        inc     dword [edi + 8]
388
        inc     dword [edi + 4]
389
 
390
        push    edi ecx
391
        mov     edi, edx                                ; Zero out till the name field.
392
        xor     eax, eax
393
        mov     ecx, 40 / 4
394
        rep stosd
395
        pop     ecx edi
396
 
397
        push    ebx edi edx
398
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]       ; Get the child inode.
399
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
400
        call    ext2_inode_read
401
        test    eax, eax
402
        jnz     .error_read_subinode
403
 
404
        lea     edi, [edx + 8]
405
 
406
        mov     eax, [ebx + EXT2_INODE_STRUC.i_ctime]   ; Convert time in NTFS format.
407
        xor     edx, edx
408
        add     eax, 3054539008                         ; (369 * 365 + 89) * 24 * 3600
409
        adc     edx, 2
410
        call    ntfs_datetime_to_bdfe.sec
411
 
412
        mov     eax, [ebx + EXT2_INODE_STRUC.i_atime]
413
        xor     edx, edx
414
        add     eax, 3054539008
415
        adc     edx, 2
416
        call    ntfs_datetime_to_bdfe.sec
417
 
418
        mov     eax, [ebx + EXT2_INODE_STRUC.i_mtime]
419
        xor     edx, edx
420
        add     eax, 3054539008
421
        adc     edx, 2
422
        call    ntfs_datetime_to_bdfe.sec
423
 
424
        pop     edx
425
        test    [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size.
426
        jnz     @F
427
 
428
        mov     eax, [ebx + EXT2_INODE_STRUC.i_size]    ; Low size
429
        stosd
430
        mov     eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ; High size
431
        stosd
432
 
433
        xor     dword [edx], FS_FT_DIR                  ; Mark as file.
434
    @@:
435
        xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
436
 
437
        ; Copy name after converting from UTF-8 to CP866.
438
        push    ecx esi
439
        mov     esi, [esp + 12]
440
        movzx   ecx, [esi + EXT2_DIR_STRUC.name_len]
441
        lea     edi, [edx + 40]
442
        lea     esi, [esi + EXT2_DIR_STRUC.name]
443
        call    utf8_to_cp866
444
        and     byte [edi], 0
445
        pop     esi ecx edi ebx
446
 
447
        cmp     byte [edx + 40], '.'                    ; If it begins with ".", mark it as hidden.
448
        jne     @F
449
        or      dword [edx], FS_FT_HIDDEN
450
 
451
    @@:
452
        add     edx, 40 + 264                           ; Go to next record.
453
        dec     ecx
454
    .empty_rec:
455
        movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
456
 
457
        cmp     eax, 12                                 ; Illegal length.
458
        jb      .error_bad_len
459
        test    eax, 0x3                                ; Not a multiple of four.
460
        jnz     .error_bad_len
461
 
462
        sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract directly from the inode.
463
        add     ebx, eax
464
        cmp     ebx, [edi + 24]                         ; Are we at the end of the block?
465
        jb      .wanted_start
466
 
467
        push    .wanted_start
468
        jmp     .end_block
469
 
470
    .end_dir:                                           ; End of the directory.
471
        call    ext2_unlock
472
        mov     edx, [edi + 28]                         ; Address of where to return data.
473
        mov     ebx, [edi + 8]                          ; EXT2_read_in_folder
474
        mov     ecx, [edi + 4]                          ; EXT2_files_in_folder
475
        mov     dword [edx], 1                          ; Version
476
        mov     [edx + 4], ebx
477
        mov     [edx + 8], ecx
478
 
479
        lea     esp, [edi + 32]
480
 
481
        xor     eax, eax                                ; Reserved in current implementation.
482
        lea     edi, [edx + 12]
483
        mov     ecx, 20 / 4
484
        rep stosd
485
        ret
486
 
487
    .error_bad_len:
488
        mov     eax, ERROR_FS_FAIL
489
 
490
    .error_read_subinode:
491
    .error_get_block:
492
        ; Fix the stack.
493
        lea     esp, [edi + 32]
494
 
495
    .error_ret:
496
        or      ebx, -1
497
        push    eax
498
        call    ext2_unlock
499
        pop     eax
500
 
501
        ret
502
 
503
    .error_empty_dir:                                   ; inode of folder without blocks.
504
    .error_root:                                        ; Root has to be a folder.
505
        mov     eax, ERROR_FS_FAIL
506
        jmp     .error_ret
507
 
508
    .error_not_found:                                   ; Directory not found.
509
        mov     eax, ERROR_FILE_NOT_FOUND
510
        jmp     .error_ret
511
 
512
;---------------------------------------------------------------------
513
; Read file from the hard disk.
514
; Input:        esi + [esp + 4] = points to file name.
515
;               ebx = pointer to paramteres from sysfunc 70.
516
;               ebp = pointer to EXTFS structure.
517
; Output:       ebx = bytes read (0xFFFFFFFF -> file not found)
518
;               eax = error code (0 implies no error)
519
;---------------------------------------------------------------------
520
ext2_Read:
521
        call    ext2_lock
522
        cmp     byte [esi], 0
523
        jnz     @F
524
 
525
    .this_is_nofile:
526
        call    ext2_unlock
527
        or      ebx, -1
528
        mov     eax, ERROR_ACCESS_DENIED
529
        ret
530
 
531
    @@:
532
        push    ebx
533
        stdcall ext2_inode_find, [esp + 4 + 4]
534
        pop     ebx
535
 
536
        mov     esi, [ebp + EXTFS.ext2_save_inode]
537
        test    eax, eax
538
        jz      @F
539
 
540
        call    ext2_unlock
541
        or      ebx, -1
542
        mov     eax, ERROR_FILE_NOT_FOUND
543
        ret
544
 
545
    @@:
546
        mov     ax, [esi + EXT2_INODE_STRUC.i_mode]
547
        and     ax, EXT2_S_IFMT                         ; Leave the file format in AX.
548
 
549
        ; Check if file.
550
        cmp     ax, EXT2_S_IFREG
551
        jne     .this_is_nofile
552
 
553
        mov     edi, [ebx + 16]
554
        mov     ecx, [ebx + 12]
555
 
556
        mov     eax, [ebx + 4]
557
        mov     edx, [ebx + 8]                          ; edx:eax = start byte number.
558
 
559
        ; Check if file is big enough for us.
560
        cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
561
        ja      .size_greater
562
        jb      .size_less
563
 
564
        cmp     [esi + EXT2_INODE_STRUC.i_size], eax
565
        ja      .size_greater
566
 
567
    .size_less:
568
        call    ext2_unlock
569
        xor     ebx, ebx
570
        mov     eax, ERROR_END_OF_FILE
571
        ret
572
 
573
    @@:
574
    .size_greater:
575
        add     eax, ecx                                ; Get last byte.
576
        adc     edx, 0
577
 
578
        ; Check if we've to read whole file, or till requested.
579
        cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
580
        ja      .read_till_requested
581
        jb      .read_whole_file
582
        cmp     [esi + EXT2_INODE_STRUC.i_size], eax
583
        jae     .read_till_requested
584
 
585
    .read_whole_file:
586
        push    1                                       ; Read till the end of file.
587
        mov     ecx, [esi + EXT2_INODE_STRUC.i_size]
588
        sub     ecx, [ebx + 4]                          ; To read = (size - starting byte)
589
        jmp     @F
590
 
591
    .read_till_requested:
592
        push    0                                       ; Read as much as requested.
593
 
594
    @@:
595
        ; ecx = bytes to read.
596
        ; edi = return memory
597
        ; [esi] = starting byte.
598
 
599
        push    ecx                                     ; Number of bytes to read.
600
 
601
        ; Get part of the first block.
602
        mov     edx, [ebx + 8]
603
        mov     eax, [ebx + 4]
604
        div     [ebp + EXTFS.block_size]
605
 
606
        push    eax                                     ; Save block counter to stack.
607
 
608
        push    ecx
609
        mov     ecx, eax
610
        call    ext2_get_inode_block
611
        test    eax, eax
612
        jnz     .error_at_first_block
613
 
614
        mov     ebx, [ebp + EXTFS.ext2_save_block]
615
        mov     eax, ecx
616
        call    ext2_block_read
617
        test    eax, eax
618
        jnz     .error_at_first_block
619
 
620
        pop     ecx
621
        ; Get index inside block.
622
        add     ebx, edx
623
 
624
        neg     edx
625
        add     edx, [ebp + EXTFS.block_size]          ; Get number of bytes in this block.
626
 
627
        ; If it's smaller than total bytes to read, then only one block.
628
        cmp     ecx, edx
629
        jbe     .only_one_block
630
 
631
        mov     eax, ecx
632
        sub     eax, edx
633
        mov     ecx, edx
634
 
635
        push    esi
636
        mov     esi, ebx
637
        rep movsb                                       ; Copy part of 1st block.
638
        pop     esi
639
 
640
        ; eax -> bytes to read.
641
    .calc_blocks_count:
642
        mov     ebx, edi                                ; Read the block in ebx.
643
        xor     edx, edx
644
        div     [ebp + EXTFS.block_size]                ; Get number of bytes in last block in edx.
645
        mov     edi, eax                                ; Get number of blocks in edi.
646
 
647
    @@:
648
        ; Test if all blocks are done.
649
        test    edi, edi
650
        jz      .finish_block
651
 
652
        inc     dword [esp]
653
        mov     ecx, [esp]
654
        call    ext2_get_inode_block
655
 
656
        test    eax, eax
657
        jnz     .error_at_read_cycle
658
 
659
        mov     eax, ecx                                ; ebx already contains desired values.
660
        call    ext2_block_read
661
 
662
        test    eax, eax
663
        jnz     .error_at_read_cycle
664
 
665
        add     ebx, [ebp + EXTFS.block_size]
666
 
667
        dec     edi
668
        jmp     @B
669
 
670
    ; In edx -- number of bytes in the last block.
671
    .finish_block:
672
        test    edx, edx
673
        jz      .end_read
674
 
675
        pop     ecx                                     ; Pop block counter in ECX.
676
        inc     ecx
677
        call    ext2_get_inode_block
678
 
679
        test    eax, eax
680
        jnz     .error_at_finish_block
681
 
682
        mov     edi, ebx
683
        mov     eax, ecx
684
        mov     ebx, [ebp + EXTFS.ext2_save_block]
685
        call    ext2_block_read
686
 
687
        test    eax, eax
688
        jnz     .error_at_finish_block
689
 
690
        mov     ecx, edx
691
        mov     esi, ebx
692
        rep movsb                                       ; Copy last piece of block.
693
        jmp     @F
694
 
695
    .end_read:
696
        pop     ecx                                     ; Pop block counter in ECX.
697
    @@:
698
        pop     ebx                                     ; Number of bytes read.
699
        call    ext2_unlock
700
        pop     eax                                     ; If we were asked to read more, say EOF.
701
        test    eax, eax
702
        jz      @F
703
 
704
        mov     eax, ERROR_END_OF_FILE
705
        ret
706
    @@:
707
        xor     eax, eax
708
        ret
709
 
710
    .only_one_block:
711
        mov     esi, ebx
712
        rep movsb                                       ; Copy last piece of block.
713
        jmp     .end_read
714
 
715
    .error_at_first_block:
716
        pop     edx
717
    .error_at_read_cycle:
718
        pop     ebx
719
    .error_at_finish_block:
720
        pop     ecx edx
721
        or      ebx, -1
722
        push    eax
723
        call    ext2_unlock
724
        pop     eax
725
        ret
726
 
727
;---------------------------------------------------------------------
728
; Read file information from block device.
729
; Input:        esi + [esp + 4] = file name.
730
;               ebx = pointer to paramteres from sysfunc 70.
731
;               ebp = pointer to EXTFS structure.
732
; Output:       eax = error code.
733
;---------------------------------------------------------------------
734
ext2_GetFileInfo:
735
        call    ext2_lock
736
        mov     edx, [ebx + 16]
737
        cmp     byte [esi], 0
738
        jz      .is_root
739
 
740
        push    edx
741
        stdcall ext2_inode_find, [esp + 4 + 4]
742
        mov     ebx, edx
743
        pop     edx
744
 
745
        mov     esi, [ebp + EXTFS.ext2_save_inode]
746
        test    eax, eax
747
        jz      @F
748
 
749
        push    eax
750
        call    ext2_unlock
751
        pop     eax
752
        ret
753
 
754
    .is_root:
755
        xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
756
        mov     esi, [ebp + EXTFS.root_inode]
757
 
758
    @@:
759
        xor     eax, eax
760
        mov     edi, edx
761
        mov     ecx, 40/4
762
        rep stosd                                       ; Zero fill buffer.
763
 
764
        cmp     bl, '.'
765
        jne     @F
766
        or      dword [edx], FS_FT_HIDDEN
767
 
768
    @@:
769
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
770
        jnz     @F                                      ; If a directory, don't put in file size.
771
 
772
        mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
773
        mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
774
        mov     dword [edx+32], eax
775
        mov     dword [edx+36], ebx
776
 
777
        xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
778
    @@:
779
        xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
780
 
781
        lea     edi, [edx + 8]
782
 
783
        ; Store all time.
784
        mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
785
        xor     edx, edx
786
        add     eax, 3054539008
787
        adc     edx, 2
788
        call    ntfs_datetime_to_bdfe.sec
789
 
790
        mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
791
        xor     edx, edx
792
        add     eax, 3054539008
793
        adc     edx, 2
794
        call    ntfs_datetime_to_bdfe.sec
795
 
796
        mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
797
        xor     edx, edx
798
        add     eax, 3054539008
799
        adc     edx, 2
800
        call    ntfs_datetime_to_bdfe.sec
801
 
802
        call    ext2_unlock
803
        xor     eax, eax
804
        ret
805
 
806
;---------------------------------------------------------------------
807
; Set file information for block device.
808
; Input:        esi + [esp + 4] = file name.
809
;               ebx = pointer to paramteres from sysfunc 70.
810
;               ebp = pointer to EXTFS structure.
811
; Output:       eax = error code.
812
;---------------------------------------------------------------------
813
ext2_SetFileInfo:
814
        push    edx esi edi ebx
815
        call    ext2_lock
816
        mov     edx, [ebx + 16]
817
 
818
        ; Is this read-only?
819
        test    [ebp + EXTFS.partition_flags], EXT2_RO
820
        jnz     .fail
821
 
822
        ; Not supported for root.
823
        cmp     byte [esi], 0
824
        je      .fail
825
 
826
    .get_inode:
827
        push    edx
828
        stdcall ext2_inode_find, [esp + 4 + 20]
829
        pop     edx
830
 
831
        test    eax, eax
832
        jnz     @F
833
 
834
        ; Save inode number.
835
        push    esi
836
        mov     esi, [ebp + EXTFS.ext2_save_inode]
837
 
838
        ; From the BDFE, we ignore read-only file flags, hidden file flags;
839
        ; We ignore system file flags, file was archived or not.
840
 
841
        ; Also ignored is file creation time. ext2 stores "inode modification"
842
        ; time in the ctime field, which is updated by the respective inode_write
843
        ; procedure, and any writes on it would be overwritten anyway.
844
 
845
        ; Access time.
846
        lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
847
        lea     esi, [edx + 16]
848
        call    bdfe_to_unix_time
849
 
850
        ; Modification time.
851
        add     esi, 8
852
        add     edi, 8
853
        call    bdfe_to_unix_time
854
 
855
        mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
856
        pop     eax                             ; Get inode number in eax.
857
        call    ext2_inode_write                ; eax contains error code, if any.
858
        test    eax, eax
859
        jnz     @F
860
 
861
        call    ext2_sb_update
862
        ; Sync the disk.
863
        mov     esi, [ebp + PARTITION.Disk]
864
        call    disk_sync                       ; eax contains error code, if any.
865
 
866
    @@:
867
        push    eax
868
        call    ext2_unlock
869
        pop     eax
870
 
871
        pop     ebx edi esi edx
872
        ret
873
 
874
    .fail:
875
        call    ext2_sb_update
876
        ; Sync the disk.
877
        mov     esi, [ebp + PARTITION.Disk]
878
        call    disk_sync                       ; eax contains error code, if any.
879
 
880
        mov     eax, ERROR_UNSUPPORTED_FS
881
        jmp     @B
882
 
883
;---------------------------------------------------------------------
884
; Set file information for block device.
885
; Input:        esi + [esp + 4] = file name.
886
;               ebx = pointer to paramteres from sysfunc 70.
887
;               ebp = pointer to EXTFS structure.
888
; Output:       eax = error code.
889
;---------------------------------------------------------------------
890
ext2_Delete:
891
        push    ebx ecx edx esi edi
892
        call    ext2_lock
893
 
894
        add     esi, [esp + 20 + 4]
895
 
896
        ; Can't delete root.
897
        cmp     byte [esi], 0
898
        jz      .error_access_denied
899
 
900
        push    esi
901
        stdcall ext2_inode_find, 0
902
        mov     ebx, esi
903
        pop     esi
904
 
905
        test    eax, eax
906
        jnz     .error_access_denied
907
 
908
        mov     edx, [ebp + EXTFS.ext2_save_inode]
909
        movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
910
        and     edx, EXT2_S_IFMT                                ; Get the mask.
911
        cmp     edx, EXT2_S_IFDIR
912
        jne     @F                                              ; If not a directory, we don't need to check if it's empty.
913
 
914
        call    ext2_dir_empty                                  ; 0 means directory is empty.
915
 
916
        test    eax, eax
917
        jnz     .error_access_denied
918
 
919
    @@:
920
        ; Find parent.
921
        call    ext2_inode_find_parent
922
        test    eax, eax
923
        jnz     .error_access_denied
924
        mov     eax, esi
925
 
926
        ; Save file/dir & parent inode.
927
        push    ebx eax
928
 
929
        cmp     edx, EXT2_S_IFDIR
930
        jne     @F
931
 
932
        ; Unlink '.'
933
        mov     eax, [esp + 4]
934
        call    ext2_inode_unlink
935
        cmp     eax, 0xFFFFFFFF
936
        je      .error_stack8
937
 
938
        ; Unlink '..'
939
        mov     eax, [esp + 4]
940
        mov     ebx, [esp]
941
        call    ext2_inode_unlink
942
        cmp     eax, 0xFFFFFFFF
943
        je      .error_stack8
944
 
945
    @@:
946
        pop     eax
947
        mov     ebx, [esp]
948
        ; Unlink the inode.
949
        call    ext2_inode_unlink
950
        cmp     eax, 0xFFFFFFFF
951
        je      .error_stack4
952
 
953
        ; If hardlinks aren't zero, shouldn't completely free.
954
        test    eax, eax
955
        jz      @F
956
 
957
        add     esp, 4
958
        jmp     .disk_sync
959
 
960
    @@:
961
        ; Read the inode.
962
        mov     eax, [esp]
963
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
964
        call    ext2_inode_read
965
        test    eax, eax
966
        jnz     .error_stack4
967
 
968
        ; Free inode data.
969
        mov     esi, [ebp + EXTFS.ext2_save_inode]
970
        xor     ecx, ecx
971
 
972
    @@:
973
        push    ecx
974
        call    ext2_get_inode_block
975
        test    eax, eax
976
        jnz     .error_stack8
977
        mov     eax, ecx
978
        pop     ecx
979
 
980
        ; If 0, we're done.
981
        test    eax, eax
982
        jz      @F
983
 
984
        call    ext2_block_free
985
        test    eax, eax
986
        jnz     .error_stack4
987
 
988
        inc     ecx
989
        jmp     @B
990
 
991
    @@:
992
        ; Clear the inode, and add deletion time.
993
        mov     edi, [ebp + EXTFS.ext2_save_inode]
994
        xor     eax, eax
995
        mov     ecx, [ebp + EXTFS.inode_size]
996
        rep stosb
997
 
998
        mov     edi, [ebp + EXTFS.ext2_save_inode]
999
        add     edi, EXT2_INODE_STRUC.i_dtime
1000
        call    current_unix_time
1001
 
1002
        ; Write the inode.
1003
        mov     eax, [esp]
1004
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
1005
        call    ext2_inode_write
1006
        test    eax, eax
1007
        jnz     .error_stack4
1008
 
1009
        ; Check if directory.
1010
        cmp     edx, EXT2_S_IFDIR
1011
        jne     @F
1012
 
1013
        ; If it is, decrement used_dirs_count.
1014
 
1015
        ; Get block group.
1016
        mov     eax, [esp]
1017
        dec     eax
1018
        xor     edx, edx
1019
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1020
 
1021
        push    eax
1022
        call    ext2_bg_read_desc
1023
        test    eax, eax
1024
        jz      .error_stack8
1025
 
1026
        dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1027
 
1028
        pop     eax
1029
        call    ext2_bg_write_desc
1030
 
1031
    @@:
1032
        pop     eax
1033
        call    ext2_inode_free
1034
        test    eax, eax
1035
        jnz     .error_access_denied
1036
 
1037
    .disk_sync:
1038
        call    ext2_sb_update
1039
 
1040
        ; Sync the disk.
1041
        mov     esi, [ebp + PARTITION.Disk]
1042
        call    disk_sync                       ; eax contains error code, if any.
1043
 
1044
    .return:
1045
        push    eax
1046
        call    ext2_unlock
1047
        pop     eax
1048
 
1049
        pop     edi esi edx ecx ebx
1050
        ret
1051
 
1052
    .error_stack8:
1053
        add     esp, 4
1054
    .error_stack4:
1055
        add     esp, 4
1056
    .error_access_denied:
1057
        call    ext2_sb_update
1058
 
1059
        ; Sync the disk.
1060
        mov     esi, [ebp + PARTITION.Disk]
1061
        call    disk_sync                       ; eax contains error code, if any.
1062
 
1063
        mov     eax, ERROR_ACCESS_DENIED
1064
        jmp     .return
1065
 
1066
;---------------------------------------------------------------------
1067
; Set file information for block device.
1068
; Input:        esi + [esp + 4] = file name.
1069
;               ebx = pointer to paramteres from sysfunc 70.
1070
;               ebp = pointer to EXTFS structure.
1071
; Output:       eax = error code.
1072
;---------------------------------------------------------------------
1073
ext2_CreateFolder:
1074
        push    ebx ecx edx esi edi
1075
        call    ext2_lock
1076
 
1077
        add     esi, [esp + 20 + 4]
1078
 
1079
        ; Can't create root, but for CreateFile already existing directory is success.
1080
        cmp     byte [esi], 0
1081
        jz      .success
1082
 
1083
        push    esi
1084
        stdcall ext2_inode_find, 0
1085
        pop     esi
1086
 
1087
        ; If the directory is there, we've succeeded.
1088
        test    eax, eax
1089
        jz      .success
1090
 
1091
        ; Find parent.
1092
        call    ext2_inode_find_parent
1093
        test    eax, eax
1094
        jnz     .error
1095
 
1096
        ; Inode ID for preference.
1097
        mov     eax, esi
1098
        call    ext2_inode_alloc
1099
        test    eax, eax
1100
        jnz     .error_full
1101
 
1102
        ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
1103
        mov     edx, ebx
1104
 
1105
        push    edi
1106
 
1107
        xor     al, al
1108
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1109
        mov     ecx, [ebp + EXTFS.inode_size]
1110
        rep stosb
1111
 
1112
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1113
        add     edi, EXT2_INODE_STRUC.i_atime
1114
        call    current_unix_time
1115
 
1116
        add     edi, 8
1117
        call    current_unix_time
1118
 
1119
        pop     edi
1120
 
1121
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1122
        mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
1123
        mov     eax, edx
1124
        call    ext2_inode_write
1125
        test    eax, eax
1126
        jnz     .error
1127
 
1128
        ; Link to self.
1129
        push    edx esi
1130
 
1131
        mov     eax, edx
1132
        mov     ebx, eax
1133
        mov     dl, EXT2_FT_DIR
1134
        mov     esi, self_link
1135
        call    ext2_inode_link
1136
 
1137
        pop     esi edx
1138
 
1139
        test    eax, eax
1140
        jnz     .error
1141
 
1142
        ; Link to parent.
1143
        push    edx esi
1144
 
1145
        mov     eax, ebx
1146
        mov     ebx, esi
1147
        mov     dl, EXT2_FT_DIR
1148
        mov     esi, parent_link
1149
        call    ext2_inode_link
1150
 
1151
        pop     esi edx
1152
 
1153
        test    eax, eax
1154
        jnz     .error
1155
 
1156
        ; Link parent to child.
1157
        mov     eax, esi
1158
        mov     ebx, edx
1159
        mov     esi, edi
1160
        mov     dl, EXT2_FT_DIR
1161
        call    ext2_inode_link
1162
        test    eax, eax
1163
        jnz     .error
1164
 
1165
        ; Get block group descriptor for allocated inode's block.
1166
        mov     eax, ebx
1167
        dec     eax
1168
        xor     edx, edx
1169
 
1170
        ; EAX = block group.
1171
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1172
        mov     edx, eax
1173
 
1174
        call    ext2_bg_read_desc
1175
        test    eax, eax
1176
        jz      .error
1177
 
1178
        inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1179
        mov     eax, edx
1180
        call    ext2_bg_write_desc
1181
        test    eax, eax
1182
        jnz     .error
1183
 
1184
    .success:
1185
        call    ext2_sb_update
1186
 
1187
        ; Sync the disk.
1188
        mov     esi, [ebp + PARTITION.Disk]
1189
        call    disk_sync                       ; eax contains error code, if any.
1190
 
1191
    .return:
1192
        push    eax
1193
        call    ext2_unlock
1194
        pop     eax
1195
 
1196
        pop     edi esi edx ecx ebx
1197
        ret
1198
 
1199
    .error:
1200
        call    ext2_sb_update
1201
 
1202
        ; Sync the disk.
1203
        mov     esi, [ebp + PARTITION.Disk]
1204
        call    disk_sync                       ; eax contains error code, if any.
1205
 
1206
        mov     eax, ERROR_ACCESS_DENIED
1207
        jmp     .return
1208
 
1209
    .error_full:
1210
        mov     eax, ERROR_DISK_FULL
1211
        jmp     .return
1212
 
1213
self_link:   db ".", 0
1214
parent_link: db "..", 0
1215
 
1216
ext2_Rewrite:
1217
ext2_Write:
1218
ext2_SetFileEnd:
1219
        xor     ebx, ebx
1220
        mov     eax, ERROR_UNSUPPORTED_FS
1221
        ret