Subversion Repositories Kolibri OS

Rev

Rev 3935 | Go to most recent revision | Details | Compare with Previous | 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'
4066 shikhin 11
include 'blocks.inc'
12
include 'inode.inc'
13
include 'resource.inc'
3935 shikhin 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
 
4066 shikhin 200
        ;call    ext2_sb_update
201
        ; Sync the disk.
202
        ;mov     esi, [ebp + PARTITION.Disk]
203
        ;call    disk_sync                       ; eax contains error code, if any.
204
 
3935 shikhin 205
        mov     eax, ebp                        ; Return pointer to EXTFS.
206
        pop     edi esi ebp ebx
207
        ret
208
 
209
    ; Error in setting up.
210
    .error:
211
        ; Free save block.
212
        KERNEL_FREE [ebp + EXTFS.ext2_save_block], .fail
213
 
214
        ; Temporary block.
215
        KERNEL_FREE [ebp + EXTFS.ext2_temp_block], .fail
216
 
217
        ; All inodes.
218
        KERNEL_FREE [ebp + EXTFS.ext2_save_inode], .fail
219
        KERNEL_FREE [ebp + EXTFS.ext2_temp_inode], .fail
220
        KERNEL_FREE [ebp + EXTFS.root_inode], .fail
221
 
222
        mov     eax, ebp
223
        call    free
224
 
225
        jmp     .fail
226
endp
227
 
228
; FUNCTIONS PROVIDED BY SYSCALLS.
229
 
230
;---------------------------------------------------------------------
231
; Frees up all ext2 structures.
232
; Input:        eax = pointer to EXTFS.
233
;---------------------------------------------------------------------
234
proc ext2_free
235
        push    ebp
236
 
237
        xchg    ebp, eax
238
        stdcall kernel_free, [ebp+EXTFS.ext2_save_block]
239
        stdcall kernel_free, [ebp+EXTFS.ext2_temp_block]
240
        stdcall kernel_free, [ebp+EXTFS.ext2_save_inode]
241
        stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode]
242
        stdcall kernel_free, [ebp+EXTFS.root_inode]
243
 
244
        xchg    ebp, eax
245
        call    free
246
 
247
        pop     ebp
248
        ret
249
endp
250
 
251
;---------------------------------------------------------------------
252
; Read disk folder.
253
; Input:        ebp = pointer to EXTFS structure.
254
;               esi + [esp + 4] = file name.
255
;               ebx = pointer to parameters from sysfunc 70.
256
; Output:       ebx = blocks read (or 0xFFFFFFFF, folder not found)
257
;               eax = error code (0 implies no error)
258
;---------------------------------------------------------------------
259
ext2_ReadFolder:
4066 shikhin 260
        ;DEBUGF  1, "Reading folder.\n"
3935 shikhin 261
        call    ext2_lock
262
        cmp     byte [esi], 0
263
        jz      .root_folder
264
 
265
        push    ebx
266
        stdcall ext2_inode_find, [esp + 4 + 4]            ; Get inode.
267
        pop     ebx
268
 
269
        mov     esi, [ebp + EXTFS.ext2_save_inode]
270
        test    eax, eax
271
        jnz     .error_ret
272
 
273
        ; If not a directory, then return with error.
274
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
275
        jz      .error_not_found
276
        jmp     @F
277
 
278
    .root_folder:
279
        mov     esi, [ebp + EXTFS.root_inode]
280
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
281
        jz      .error_root
282
 
283
        ; Copy the inode.
284
        mov     edi, [ebp + EXTFS.ext2_save_inode]
285
        mov     ecx, [ebp + EXTFS.inode_size]
286
        shr     ecx, 2
287
 
288
        push    edi
289
        rep movsd
290
        pop     esi
291
 
292
    @@:
293
        cmp     [esi + EXT2_INODE_STRUC.i_size], 0      ; Folder is empty.
294
        je      .error_empty_dir
295
 
296
        mov     edx, [ebx + 16]
297
        push    edx                                     ; Result address [edi + 28].
298
        push    0                                       ; End of the current block in folder [edi + 24]
299
        push    dword[ebx + 12]                         ; Blocks to read [edi + 20]
300
        push    dword[ebx + 4]                          ; The first wanted file [edi + 16]
301
        push    dword[ebx + 8]                          ; Flags [edi + 12]
302
        push    0                                       ; Read files [edi + 8]
303
        push    0                                       ; Files in folder [edi + 4]
304
        push    0                                       ; Number of blocks read in dir (and current block index) [edi]
305
 
306
        ; Fill header with zeroes.
307
        mov     edi, edx
308
        mov     ecx, 32/4
309
        rep stosd
310
 
311
        mov     edi, esp                                ; edi = pointer to local variables.
312
        add     edx, 32                                 ; edx = mem to return.
313
 
314
        xor     ecx, ecx                                ; Get number of first block.
4066 shikhin 315
        call    ext2_inode_get_block
3935 shikhin 316
        test    eax, eax
317
        jnz     .error_get_block
318
 
319
        mov     eax, ecx
320
        mov     ebx, [ebp + EXTFS.ext2_save_block]
321
        call    ext2_block_read                          ; Read the block.
322
        test    eax, eax
323
        jnz     .error_get_block
324
 
325
        mov     eax, ebx                                ; esi: current directory record
326
        add     eax, [ebp + EXTFS.block_size]
327
 
328
        mov     [edi + 24], eax
329
 
330
        mov     ecx, [edi + 16]                         ; ecx = first wanted (flags ommited)
331
 
332
    .find_wanted_start:
333
        jecxz   .find_wanted_end
334
 
335
    .find_wanted_cycle:
336
        cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; Don't count unused inode in total files.
337
        jz      @F
338
 
339
        inc     dword [edi + 4]                         ; EXT2 files in folder.
340
        dec     ecx
341
    @@:
342
        movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
343
 
344
        cmp     eax, 12                                 ; Minimum record length.
345
        jb      .error_bad_len
346
        test    eax, 0x3                                ; Record length must be divisible by four.
347
        jnz     .error_bad_len
348
 
349
        sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract "processed record" length directly from inode.
350
        add     ebx, eax                                ; Go to next record.
351
        cmp     ebx, [edi + 24]                         ; If not reached the next block, continue.
352
        jb      .find_wanted_start
353
 
354
        push    .find_wanted_start
355
   .end_block:                                          ; Get the next block.
356
        cmp     [esi + EXT2_INODE_STRUC.i_size], 0
357
        jle     .end_dir
358
 
359
        inc     dword [edi]                             ; Number of blocks read.
360
 
361
        ; Read the next block.
362
        push    ecx
363
        mov     ecx, [edi]
4066 shikhin 364
        call    ext2_inode_get_block
3935 shikhin 365
        test    eax, eax
366
        jnz     .error_get_block
367
 
368
        mov     eax, ecx
369
        mov     ebx, [ebp + EXTFS.ext2_save_block]
370
        call    ext2_block_read
371
        test    eax, eax
372
        jnz     .error_get_block
373
        pop     ecx
374
 
375
        mov     eax, ebx
376
        add     eax, [ebp + EXTFS.block_size]
377
        mov     [edi + 24], eax                         ; Update the end of the current block variable.
378
        ret
379
 
380
    .wanted_end:
381
        loop    .find_wanted_cycle                      ; Skip files till we reach wanted one.
382
 
383
    ; First requisite file.
384
    .find_wanted_end:
385
        mov     ecx, [edi + 20]
386
    .wanted_start:                                      ; Look for first_wanted + count.
387
        jecxz   .wanted_end
388
 
389
        cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; if (inode == 0): not used;
390
        jz      .empty_rec
391
 
392
        ; Increment "files in dir" and "read files" count.
393
        inc     dword [edi + 8]
394
        inc     dword [edi + 4]
395
 
396
        push    edi ecx
397
        mov     edi, edx                                ; Zero out till the name field.
398
        xor     eax, eax
399
        mov     ecx, 40 / 4
400
        rep stosd
401
        pop     ecx edi
402
 
403
        push    ebx edi edx
404
        mov     eax, [ebx + EXT2_DIR_STRUC.inode]       ; Get the child inode.
405
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
406
        call    ext2_inode_read
407
        test    eax, eax
408
        jnz     .error_read_subinode
409
 
410
        lea     edi, [edx + 8]
411
 
412
        mov     eax, [ebx + EXT2_INODE_STRUC.i_ctime]   ; Convert time in NTFS format.
413
        xor     edx, edx
414
        add     eax, 3054539008                         ; (369 * 365 + 89) * 24 * 3600
415
        adc     edx, 2
416
        call    ntfs_datetime_to_bdfe.sec
417
 
418
        mov     eax, [ebx + EXT2_INODE_STRUC.i_atime]
419
        xor     edx, edx
420
        add     eax, 3054539008
421
        adc     edx, 2
422
        call    ntfs_datetime_to_bdfe.sec
423
 
424
        mov     eax, [ebx + EXT2_INODE_STRUC.i_mtime]
425
        xor     edx, edx
426
        add     eax, 3054539008
427
        adc     edx, 2
428
        call    ntfs_datetime_to_bdfe.sec
429
 
430
        pop     edx
431
        test    [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size.
432
        jnz     @F
433
 
434
        mov     eax, [ebx + EXT2_INODE_STRUC.i_size]    ; Low size
435
        stosd
436
        mov     eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ; High size
437
        stosd
438
 
439
        xor     dword [edx], FS_FT_DIR                  ; Mark as file.
440
    @@:
441
        xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
442
 
443
        ; Copy name after converting from UTF-8 to CP866.
444
        push    ecx esi
445
        mov     esi, [esp + 12]
446
        movzx   ecx, [esi + EXT2_DIR_STRUC.name_len]
447
        lea     edi, [edx + 40]
448
        lea     esi, [esi + EXT2_DIR_STRUC.name]
449
        call    utf8_to_cp866
450
        and     byte [edi], 0
451
        pop     esi ecx edi ebx
452
 
453
        cmp     byte [edx + 40], '.'                    ; If it begins with ".", mark it as hidden.
454
        jne     @F
455
        or      dword [edx], FS_FT_HIDDEN
456
 
457
    @@:
458
        add     edx, 40 + 264                           ; Go to next record.
459
        dec     ecx
460
    .empty_rec:
461
        movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
462
 
463
        cmp     eax, 12                                 ; Illegal length.
464
        jb      .error_bad_len
465
        test    eax, 0x3                                ; Not a multiple of four.
466
        jnz     .error_bad_len
467
 
468
        sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract directly from the inode.
469
        add     ebx, eax
470
        cmp     ebx, [edi + 24]                         ; Are we at the end of the block?
471
        jb      .wanted_start
472
 
473
        push    .wanted_start
474
        jmp     .end_block
475
 
476
    .end_dir:                                           ; End of the directory.
477
        call    ext2_unlock
478
        mov     edx, [edi + 28]                         ; Address of where to return data.
479
        mov     ebx, [edi + 8]                          ; EXT2_read_in_folder
480
        mov     ecx, [edi + 4]                          ; EXT2_files_in_folder
481
        mov     dword [edx], 1                          ; Version
482
        mov     [edx + 4], ebx
483
        mov     [edx + 8], ecx
484
 
485
        lea     esp, [edi + 32]
486
 
487
        xor     eax, eax                                ; Reserved in current implementation.
488
        lea     edi, [edx + 12]
489
        mov     ecx, 20 / 4
490
        rep stosd
4066 shikhin 491
 
492
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 493
        ret
494
 
495
    .error_bad_len:
496
        mov     eax, ERROR_FS_FAIL
497
 
498
    .error_read_subinode:
499
    .error_get_block:
500
        ; Fix the stack.
501
        lea     esp, [edi + 32]
502
 
503
    .error_ret:
504
        or      ebx, -1
505
        push    eax
506
        call    ext2_unlock
507
        pop     eax
4066 shikhin 508
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 509
        ret
510
 
511
    .error_empty_dir:                                   ; inode of folder without blocks.
512
    .error_root:                                        ; Root has to be a folder.
513
        mov     eax, ERROR_FS_FAIL
514
        jmp     .error_ret
515
 
516
    .error_not_found:                                   ; Directory not found.
517
        mov     eax, ERROR_FILE_NOT_FOUND
518
        jmp     .error_ret
519
 
520
;---------------------------------------------------------------------
521
; Read file from the hard disk.
522
; Input:        esi + [esp + 4] = points to file name.
523
;               ebx = pointer to paramteres from sysfunc 70.
524
;               ebp = pointer to EXTFS structure.
525
; Output:       ebx = bytes read (0xFFFFFFFF -> file not found)
526
;               eax = error code (0 implies no error)
527
;---------------------------------------------------------------------
528
ext2_Read:
4066 shikhin 529
        ;DEBUGF  1, "Attempting read.\n"
3935 shikhin 530
        call    ext2_lock
531
        cmp     byte [esi], 0
532
        jnz     @F
533
 
534
    .this_is_nofile:
535
        call    ext2_unlock
536
        or      ebx, -1
537
        mov     eax, ERROR_ACCESS_DENIED
538
        ret
539
 
540
    @@:
541
        push    ebx
542
        stdcall ext2_inode_find, [esp + 4 + 4]
543
        pop     ebx
544
 
545
        mov     esi, [ebp + EXTFS.ext2_save_inode]
546
        test    eax, eax
547
        jz      @F
548
 
549
        call    ext2_unlock
550
        or      ebx, -1
551
        mov     eax, ERROR_FILE_NOT_FOUND
552
        ret
553
 
554
    @@:
555
        mov     ax, [esi + EXT2_INODE_STRUC.i_mode]
556
        and     ax, EXT2_S_IFMT                         ; Leave the file format in AX.
557
 
558
        ; Check if file.
559
        cmp     ax, EXT2_S_IFREG
560
        jne     .this_is_nofile
561
 
562
        mov     edi, [ebx + 16]
563
        mov     ecx, [ebx + 12]
564
 
565
        mov     eax, [ebx + 4]
566
        mov     edx, [ebx + 8]                          ; edx:eax = start byte number.
567
 
568
        ; Check if file is big enough for us.
569
        cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
570
        ja      .size_greater
571
        jb      .size_less
572
 
573
        cmp     [esi + EXT2_INODE_STRUC.i_size], eax
574
        ja      .size_greater
575
 
576
    .size_less:
577
        call    ext2_unlock
578
        xor     ebx, ebx
579
        mov     eax, ERROR_END_OF_FILE
580
        ret
581
 
582
    @@:
583
    .size_greater:
584
        add     eax, ecx                                ; Get last byte.
585
        adc     edx, 0
586
 
587
        ; Check if we've to read whole file, or till requested.
588
        cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
589
        ja      .read_till_requested
590
        jb      .read_whole_file
591
        cmp     [esi + EXT2_INODE_STRUC.i_size], eax
592
        jae     .read_till_requested
593
 
594
    .read_whole_file:
595
        push    1                                       ; Read till the end of file.
596
        mov     ecx, [esi + EXT2_INODE_STRUC.i_size]
597
        sub     ecx, [ebx + 4]                          ; To read = (size - starting byte)
598
        jmp     @F
599
 
600
    .read_till_requested:
601
        push    0                                       ; Read as much as requested.
602
 
603
    @@:
604
        ; ecx = bytes to read.
605
        ; edi = return memory
606
        ; [esi] = starting byte.
607
 
608
        push    ecx                                     ; Number of bytes to read.
609
 
610
        ; Get part of the first block.
611
        mov     edx, [ebx + 8]
612
        mov     eax, [ebx + 4]
613
        div     [ebp + EXTFS.block_size]
614
 
615
        push    eax                                     ; Save block counter to stack.
616
 
617
        push    ecx
618
        mov     ecx, eax
4066 shikhin 619
        call    ext2_inode_get_block
3935 shikhin 620
        test    eax, eax
621
        jnz     .error_at_first_block
622
 
623
        mov     ebx, [ebp + EXTFS.ext2_save_block]
624
        mov     eax, ecx
625
        call    ext2_block_read
626
        test    eax, eax
627
        jnz     .error_at_first_block
628
 
629
        pop     ecx
630
        ; Get index inside block.
631
        add     ebx, edx
632
 
633
        neg     edx
634
        add     edx, [ebp + EXTFS.block_size]          ; Get number of bytes in this block.
635
 
636
        ; If it's smaller than total bytes to read, then only one block.
637
        cmp     ecx, edx
638
        jbe     .only_one_block
639
 
640
        mov     eax, ecx
641
        sub     eax, edx
642
        mov     ecx, edx
643
 
644
        push    esi
645
        mov     esi, ebx
646
        rep movsb                                       ; Copy part of 1st block.
647
        pop     esi
648
 
649
        ; eax -> bytes to read.
650
    .calc_blocks_count:
651
        mov     ebx, edi                                ; Read the block in ebx.
652
        xor     edx, edx
653
        div     [ebp + EXTFS.block_size]                ; Get number of bytes in last block in edx.
654
        mov     edi, eax                                ; Get number of blocks in edi.
655
 
656
    @@:
657
        ; Test if all blocks are done.
658
        test    edi, edi
659
        jz      .finish_block
660
 
661
        inc     dword [esp]
662
        mov     ecx, [esp]
4066 shikhin 663
        call    ext2_inode_get_block
3935 shikhin 664
 
665
        test    eax, eax
666
        jnz     .error_at_read_cycle
667
 
668
        mov     eax, ecx                                ; ebx already contains desired values.
669
        call    ext2_block_read
670
 
671
        test    eax, eax
672
        jnz     .error_at_read_cycle
673
 
674
        add     ebx, [ebp + EXTFS.block_size]
675
 
676
        dec     edi
677
        jmp     @B
678
 
679
    ; In edx -- number of bytes in the last block.
680
    .finish_block:
681
        test    edx, edx
682
        jz      .end_read
683
 
684
        pop     ecx                                     ; Pop block counter in ECX.
685
        inc     ecx
4066 shikhin 686
        call    ext2_inode_get_block
3935 shikhin 687
 
688
        test    eax, eax
689
        jnz     .error_at_finish_block
690
 
691
        mov     edi, ebx
692
        mov     eax, ecx
693
        mov     ebx, [ebp + EXTFS.ext2_save_block]
694
        call    ext2_block_read
695
 
696
        test    eax, eax
697
        jnz     .error_at_finish_block
698
 
699
        mov     ecx, edx
700
        mov     esi, ebx
701
        rep movsb                                       ; Copy last piece of block.
702
        jmp     @F
703
 
704
    .end_read:
705
        pop     ecx                                     ; Pop block counter in ECX.
706
    @@:
707
        pop     ebx                                     ; Number of bytes read.
708
        call    ext2_unlock
709
        pop     eax                                     ; If we were asked to read more, say EOF.
710
        test    eax, eax
711
        jz      @F
712
 
713
        mov     eax, ERROR_END_OF_FILE
714
        ret
715
    @@:
716
        xor     eax, eax
4066 shikhin 717
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 718
        ret
719
 
720
    .only_one_block:
721
        mov     esi, ebx
722
        rep movsb                                       ; Copy last piece of block.
723
        jmp     .end_read
724
 
725
    .error_at_first_block:
726
        pop     edx
727
    .error_at_read_cycle:
728
        pop     ebx
729
    .error_at_finish_block:
730
        pop     ecx edx
731
        or      ebx, -1
732
        push    eax
733
        call    ext2_unlock
734
        pop     eax
4066 shikhin 735
 
736
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 737
        ret
738
 
739
;---------------------------------------------------------------------
740
; Read file information from block device.
741
; Input:        esi + [esp + 4] = file name.
742
;               ebx = pointer to paramteres from sysfunc 70.
743
;               ebp = pointer to EXTFS structure.
744
; Output:       eax = error code.
745
;---------------------------------------------------------------------
746
ext2_GetFileInfo:
4066 shikhin 747
        ;DEBUGF  1, "Calling for file info.\n"
3935 shikhin 748
        call    ext2_lock
749
        mov     edx, [ebx + 16]
750
        cmp     byte [esi], 0
751
        jz      .is_root
752
 
753
        push    edx
754
        stdcall ext2_inode_find, [esp + 4 + 4]
755
        mov     ebx, edx
756
        pop     edx
757
 
758
        mov     esi, [ebp + EXTFS.ext2_save_inode]
759
        test    eax, eax
760
        jz      @F
761
 
762
        push    eax
763
        call    ext2_unlock
764
        pop     eax
4066 shikhin 765
 
766
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 767
        ret
768
 
769
    .is_root:
770
        xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
771
        mov     esi, [ebp + EXTFS.root_inode]
772
 
773
    @@:
774
        xor     eax, eax
775
        mov     edi, edx
776
        mov     ecx, 40/4
777
        rep stosd                                       ; Zero fill buffer.
778
 
779
        cmp     bl, '.'
780
        jne     @F
781
        or      dword [edx], FS_FT_HIDDEN
782
 
783
    @@:
784
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
785
        jnz     @F                                      ; If a directory, don't put in file size.
786
 
787
        mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
788
        mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
789
        mov     dword [edx+32], eax
790
        mov     dword [edx+36], ebx
791
 
792
        xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
793
    @@:
794
        xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
795
 
796
        lea     edi, [edx + 8]
797
 
798
        ; Store all time.
799
        mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
800
        xor     edx, edx
801
        add     eax, 3054539008
802
        adc     edx, 2
803
        call    ntfs_datetime_to_bdfe.sec
804
 
805
        mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
806
        xor     edx, edx
807
        add     eax, 3054539008
808
        adc     edx, 2
809
        call    ntfs_datetime_to_bdfe.sec
810
 
811
        mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
812
        xor     edx, edx
813
        add     eax, 3054539008
814
        adc     edx, 2
815
        call    ntfs_datetime_to_bdfe.sec
816
 
817
        call    ext2_unlock
818
        xor     eax, eax
4066 shikhin 819
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 820
        ret
821
 
822
;---------------------------------------------------------------------
823
; Set file information for block device.
824
; Input:        esi + [esp + 4] = file name.
825
;               ebx = pointer to paramteres from sysfunc 70.
826
;               ebp = pointer to EXTFS structure.
827
; Output:       eax = error code.
828
;---------------------------------------------------------------------
829
ext2_SetFileInfo:
4066 shikhin 830
        test    [ebp + EXTFS.partition_flags], EXT2_RO
831
        jz      @F
832
 
833
        mov     eax, ERROR_UNSUPPORTED_FS
834
        ret
835
 
836
    @@:
3935 shikhin 837
        push    edx esi edi ebx
838
        call    ext2_lock
839
        mov     edx, [ebx + 16]
840
 
841
        ; Is this read-only?
842
        test    [ebp + EXTFS.partition_flags], EXT2_RO
843
        jnz     .fail
844
 
845
        ; Not supported for root.
846
        cmp     byte [esi], 0
847
        je      .fail
848
 
849
    .get_inode:
850
        push    edx
851
        stdcall ext2_inode_find, [esp + 4 + 20]
852
        pop     edx
853
 
854
        test    eax, eax
855
        jnz     @F
856
 
857
        ; Save inode number.
858
        push    esi
859
        mov     esi, [ebp + EXTFS.ext2_save_inode]
860
 
861
        ; From the BDFE, we ignore read-only file flags, hidden file flags;
862
        ; We ignore system file flags, file was archived or not.
863
 
864
        ; Also ignored is file creation time. ext2 stores "inode modification"
865
        ; time in the ctime field, which is updated by the respective inode_write
866
        ; procedure, and any writes on it would be overwritten anyway.
867
 
868
        ; Access time.
869
        lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
870
        lea     esi, [edx + 16]
871
        call    bdfe_to_unix_time
872
 
873
        ; Modification time.
874
        add     esi, 8
875
        add     edi, 8
876
        call    bdfe_to_unix_time
877
 
878
        mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
879
        pop     eax                             ; Get inode number in eax.
880
        call    ext2_inode_write                ; eax contains error code, if any.
881
        test    eax, eax
882
        jnz     @F
883
 
884
        call    ext2_sb_update
885
        ; Sync the disk.
886
        mov     esi, [ebp + PARTITION.Disk]
887
        call    disk_sync                       ; eax contains error code, if any.
888
 
889
    @@:
890
        push    eax
891
        call    ext2_unlock
892
        pop     eax
893
 
894
        pop     ebx edi esi edx
895
        ret
896
 
897
    .fail:
898
        call    ext2_sb_update
899
        ; Sync the disk.
900
        mov     esi, [ebp + PARTITION.Disk]
901
        call    disk_sync                       ; eax contains error code, if any.
902
 
903
        mov     eax, ERROR_UNSUPPORTED_FS
904
        jmp     @B
905
 
906
;---------------------------------------------------------------------
907
; Set file information for block device.
908
; Input:        esi + [esp + 4] = file name.
909
;               ebx = pointer to paramteres from sysfunc 70.
910
;               ebp = pointer to EXTFS structure.
911
; Output:       eax = error code.
912
;---------------------------------------------------------------------
913
ext2_Delete:
4066 shikhin 914
        ;DEBUGF  1, "Attempting Delete.\n"
915
        test    [ebp + EXTFS.partition_flags], EXT2_RO
916
        jz      @F
917
 
918
        mov     eax, ERROR_UNSUPPORTED_FS
919
        ret
920
 
921
    @@:
3935 shikhin 922
        push    ebx ecx edx esi edi
923
        call    ext2_lock
924
 
925
        add     esi, [esp + 20 + 4]
926
 
927
        ; Can't delete root.
928
        cmp     byte [esi], 0
929
        jz      .error_access_denied
930
 
931
        push    esi
932
        stdcall ext2_inode_find, 0
933
        mov     ebx, esi
934
        pop     esi
935
 
936
        test    eax, eax
937
        jnz     .error_access_denied
938
 
939
        mov     edx, [ebp + EXTFS.ext2_save_inode]
940
        movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
941
        and     edx, EXT2_S_IFMT                                ; Get the mask.
942
        cmp     edx, EXT2_S_IFDIR
943
        jne     @F                                              ; If not a directory, we don't need to check if it's empty.
944
 
945
        call    ext2_dir_empty                                  ; 0 means directory is empty.
946
 
947
        test    eax, eax
948
        jnz     .error_access_denied
949
 
950
    @@:
951
        ; Find parent.
952
        call    ext2_inode_find_parent
953
        test    eax, eax
954
        jnz     .error_access_denied
955
        mov     eax, esi
956
 
957
        ; Save file/dir & parent inode.
958
        push    ebx eax
959
 
960
        cmp     edx, EXT2_S_IFDIR
961
        jne     @F
962
 
963
        ; Unlink '.'
964
        mov     eax, [esp + 4]
965
        call    ext2_inode_unlink
966
        cmp     eax, 0xFFFFFFFF
967
        je      .error_stack8
968
 
969
        ; Unlink '..'
970
        mov     eax, [esp + 4]
971
        mov     ebx, [esp]
972
        call    ext2_inode_unlink
973
        cmp     eax, 0xFFFFFFFF
974
        je      .error_stack8
975
 
976
    @@:
977
        pop     eax
978
        mov     ebx, [esp]
979
        ; Unlink the inode.
980
        call    ext2_inode_unlink
981
        cmp     eax, 0xFFFFFFFF
982
        je      .error_stack4
983
 
984
        ; If hardlinks aren't zero, shouldn't completely free.
985
        test    eax, eax
986
        jz      @F
987
 
988
        add     esp, 4
989
        jmp     .disk_sync
990
 
991
    @@:
992
        ; Read the inode.
993
        mov     eax, [esp]
994
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
995
        call    ext2_inode_read
996
        test    eax, eax
997
        jnz     .error_stack4
998
 
999
        ; Free inode data.
1000
        mov     esi, [ebp + EXTFS.ext2_save_inode]
1001
        xor     ecx, ecx
1002
 
1003
    @@:
1004
        push    ecx
4066 shikhin 1005
        call    ext2_inode_get_block
3935 shikhin 1006
        test    eax, eax
1007
        jnz     .error_stack8
1008
        mov     eax, ecx
1009
        pop     ecx
1010
 
1011
        ; If 0, we're done.
1012
        test    eax, eax
1013
        jz      @F
1014
 
1015
        call    ext2_block_free
1016
        test    eax, eax
1017
        jnz     .error_stack4
1018
 
1019
        inc     ecx
1020
        jmp     @B
1021
 
1022
    @@:
4066 shikhin 1023
        ; Free indirect blocks.
1024
        call    ext2_inode_free_indirect_blocks
1025
        test    eax, eax
1026
        jnz     .error_stack4
1027
 
3935 shikhin 1028
        ; Clear the inode, and add deletion time.
1029
        mov     edi, [ebp + EXTFS.ext2_save_inode]
1030
        xor     eax, eax
1031
        mov     ecx, [ebp + EXTFS.inode_size]
1032
        rep stosb
1033
 
1034
        mov     edi, [ebp + EXTFS.ext2_save_inode]
1035
        add     edi, EXT2_INODE_STRUC.i_dtime
1036
        call    current_unix_time
1037
 
1038
        ; Write the inode.
1039
        mov     eax, [esp]
1040
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
1041
        call    ext2_inode_write
1042
        test    eax, eax
1043
        jnz     .error_stack4
1044
 
1045
        ; Check if directory.
1046
        cmp     edx, EXT2_S_IFDIR
1047
        jne     @F
1048
 
1049
        ; If it is, decrement used_dirs_count.
1050
 
1051
        ; Get block group.
1052
        mov     eax, [esp]
1053
        dec     eax
1054
        xor     edx, edx
1055
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1056
 
1057
        push    eax
1058
        call    ext2_bg_read_desc
1059
        test    eax, eax
1060
        jz      .error_stack8
1061
 
1062
        dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1063
 
1064
        pop     eax
1065
        call    ext2_bg_write_desc
1066
 
1067
    @@:
1068
        pop     eax
1069
        call    ext2_inode_free
1070
        test    eax, eax
1071
        jnz     .error_access_denied
1072
 
1073
    .disk_sync:
1074
        call    ext2_sb_update
1075
 
1076
        ; Sync the disk.
1077
        mov     esi, [ebp + PARTITION.Disk]
1078
        call    disk_sync                       ; eax contains error code, if any.
1079
 
1080
    .return:
1081
        push    eax
1082
        call    ext2_unlock
1083
        pop     eax
1084
 
1085
        pop     edi esi edx ecx ebx
4066 shikhin 1086
        ;DEBUGF  1, "And returning with: %x.\n", eax
3935 shikhin 1087
        ret
1088
 
1089
    .error_stack8:
1090
        add     esp, 4
1091
    .error_stack4:
1092
        add     esp, 4
1093
    .error_access_denied:
1094
        call    ext2_sb_update
1095
 
1096
        ; Sync the disk.
1097
        mov     esi, [ebp + PARTITION.Disk]
1098
        call    disk_sync                       ; eax contains error code, if any.
1099
 
1100
        mov     eax, ERROR_ACCESS_DENIED
1101
        jmp     .return
1102
 
1103
;---------------------------------------------------------------------
1104
; Set file information for block device.
1105
; Input:        esi + [esp + 4] = file name.
1106
;               ebx = pointer to paramteres from sysfunc 70.
1107
;               ebp = pointer to EXTFS structure.
1108
; Output:       eax = error code.
1109
;---------------------------------------------------------------------
1110
ext2_CreateFolder:
4066 shikhin 1111
        ;DEBUGF  1, "Attempting to create folder.\n"
1112
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1113
        jz      @F
1114
 
1115
        mov     eax, ERROR_UNSUPPORTED_FS
1116
        ret
1117
 
1118
    @@:
3935 shikhin 1119
        push    ebx ecx edx esi edi
1120
        call    ext2_lock
1121
 
1122
        add     esi, [esp + 20 + 4]
1123
 
4066 shikhin 1124
        ; Can't create root, but for CreateFolder already existing directory is success.
3935 shikhin 1125
        cmp     byte [esi], 0
1126
        jz      .success
1127
 
1128
        push    esi
1129
        stdcall ext2_inode_find, 0
1130
        pop     esi
1131
 
1132
        ; If the directory is there, we've succeeded.
1133
        test    eax, eax
1134
        jz      .success
1135
 
1136
        ; Find parent.
1137
        call    ext2_inode_find_parent
1138
        test    eax, eax
1139
        jnz     .error
1140
 
1141
        ; Inode ID for preference.
1142
        mov     eax, esi
1143
        call    ext2_inode_alloc
1144
        test    eax, eax
1145
        jnz     .error_full
1146
 
1147
        ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
1148
        mov     edx, ebx
1149
 
1150
        push    edi
1151
 
1152
        xor     al, al
1153
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1154
        mov     ecx, [ebp + EXTFS.inode_size]
1155
        rep stosb
1156
 
1157
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1158
        add     edi, EXT2_INODE_STRUC.i_atime
1159
        call    current_unix_time
1160
 
1161
        add     edi, 8
1162
        call    current_unix_time
1163
 
1164
        pop     edi
1165
 
1166
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1167
        mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
1168
        mov     eax, edx
1169
        call    ext2_inode_write
1170
        test    eax, eax
1171
        jnz     .error
1172
 
1173
        ; Link to self.
1174
        push    edx esi
1175
 
1176
        mov     eax, edx
1177
        mov     ebx, eax
1178
        mov     dl, EXT2_FT_DIR
1179
        mov     esi, self_link
1180
        call    ext2_inode_link
1181
 
1182
        pop     esi edx
1183
 
1184
        test    eax, eax
1185
        jnz     .error
1186
 
1187
        ; Link to parent.
1188
        push    edx esi
1189
 
1190
        mov     eax, ebx
1191
        mov     ebx, esi
1192
        mov     dl, EXT2_FT_DIR
1193
        mov     esi, parent_link
1194
        call    ext2_inode_link
1195
 
1196
        pop     esi edx
1197
 
1198
        test    eax, eax
1199
        jnz     .error
1200
 
1201
        ; Link parent to child.
1202
        mov     eax, esi
1203
        mov     ebx, edx
1204
        mov     esi, edi
1205
        mov     dl, EXT2_FT_DIR
1206
        call    ext2_inode_link
1207
        test    eax, eax
1208
        jnz     .error
1209
 
1210
        ; Get block group descriptor for allocated inode's block.
1211
        mov     eax, ebx
1212
        dec     eax
1213
        xor     edx, edx
1214
 
1215
        ; EAX = block group.
1216
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1217
        mov     edx, eax
1218
 
1219
        call    ext2_bg_read_desc
1220
        test    eax, eax
1221
        jz      .error
1222
 
1223
        inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1224
        mov     eax, edx
1225
        call    ext2_bg_write_desc
1226
        test    eax, eax
1227
        jnz     .error
1228
 
1229
    .success:
1230
        call    ext2_sb_update
1231
 
1232
        ; Sync the disk.
1233
        mov     esi, [ebp + PARTITION.Disk]
1234
        call    disk_sync                       ; eax contains error code, if any.
1235
 
1236
    .return:
1237
        push    eax
1238
        call    ext2_unlock
1239
        pop     eax
1240
 
1241
        pop     edi esi edx ecx ebx
4066 shikhin 1242
        ;DEBUGF  1, "Returning with: %x.\n", eax
3935 shikhin 1243
        ret
1244
 
1245
    .error:
1246
        call    ext2_sb_update
1247
 
1248
        ; Sync the disk.
1249
        mov     esi, [ebp + PARTITION.Disk]
1250
        call    disk_sync                       ; eax contains error code, if any.
1251
 
1252
        mov     eax, ERROR_ACCESS_DENIED
1253
        jmp     .return
1254
 
1255
    .error_full:
1256
        mov     eax, ERROR_DISK_FULL
1257
        jmp     .return
1258
 
4066 shikhin 1259
self_link   db ".", 0
1260
parent_link db "..", 0
3935 shikhin 1261
 
4066 shikhin 1262
;---------------------------------------------------------------------
1263
; Rewrite a file.
1264
; Input:        esi + [esp + 4] = file name.
1265
;               ebx = pointer to paramteres from sysfunc 70.
1266
;               ebp = pointer to EXTFS structure.
1267
; Output:       eax = error code.
1268
;               ebx = bytes written.
1269
;---------------------------------------------------------------------
3935 shikhin 1270
ext2_Rewrite:
4066 shikhin 1271
        ;DEBUGF  1, "Attempting Rewrite.\n"
1272
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1273
        jz      @F
1274
 
1275
        mov     eax, ERROR_UNSUPPORTED_FS
1276
        ret
1277
 
1278
    @@:
1279
        push    ecx edx esi edi
1280
        pushad
1281
 
1282
        call    ext2_lock
1283
 
1284
        add     esi, [esp + 16 + 32 + 4]
1285
        ; Can't create root.
1286
        cmp     byte [esi], 0
1287
        jz      .error_access_denied
1288
 
1289
        push    esi
1290
        stdcall ext2_inode_find, 0
1291
        pop     esi
1292
 
1293
        ; If the file is there, delete it.
1294
        test    eax, eax
1295
        jnz     @F
1296
 
1297
        pushad
1298
 
1299
        push    eax
1300
        call    ext2_unlock
1301
        pop     eax
1302
 
1303
        push    dword 0x00000000
1304
        call    ext2_Delete
1305
        add     esp, 4
1306
 
1307
        push    eax
1308
        call    ext2_lock
1309
        pop     eax
1310
 
1311
        test    eax, eax
1312
        jnz     .error_access_denied_delete
1313
 
1314
        popad
1315
    @@:
1316
        ; Find parent.
1317
        call    ext2_inode_find_parent
1318
        test    eax, eax
1319
        jnz     .error_access_denied
1320
 
1321
        ; Inode ID for preference.
1322
        mov     eax, esi
1323
        call    ext2_inode_alloc
1324
        test    eax, eax
1325
        jnz     .error_full
1326
 
1327
        ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
1328
        mov     edx, ebx
1329
 
1330
        push    edi
1331
 
1332
        xor     al, al
1333
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1334
        mov     ecx, [ebp + EXTFS.inode_size]
1335
        rep stosb
1336
 
1337
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1338
        add     edi, EXT2_INODE_STRUC.i_atime
1339
        call    current_unix_time
1340
 
1341
        add     edi, 8
1342
        call    current_unix_time
1343
 
1344
        pop     edi
1345
 
1346
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1347
        mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
1348
        mov     eax, edx
1349
        call    ext2_inode_write
1350
        test    eax, eax
1351
        jnz     .error
1352
 
1353
        ; Link parent to child.
1354
        mov     eax, esi
1355
        mov     ebx, edx
1356
        mov     esi, edi
1357
        mov     dl, EXT2_FT_REG_FILE
1358
        call    ext2_inode_link
1359
        test    eax, eax
1360
        jnz     .error
1361
 
1362
        popad
1363
        push    eax
1364
        call    ext2_unlock
1365
        pop     eax
1366
 
1367
        push    dword 0x00000000
1368
        call    ext2_Write
1369
        add     esp, 4
1370
 
1371
        push    eax
1372
        call    ext2_lock
1373
        pop     eax
1374
 
1375
    .success:
1376
        push    eax
1377
        call    ext2_sb_update
1378
 
1379
        ; Sync the disk.
1380
        mov     esi, [ebp + PARTITION.Disk]
1381
        call    disk_sync                       ; eax contains error code, if any.
1382
        pop     eax
1383
 
1384
    .return:
1385
        push    eax
1386
        call    ext2_unlock
1387
        pop     eax
1388
 
1389
        pop     edi esi edx ecx
1390
 
1391
        ;DEBUGF  1, "And returning with: %x.\n", eax
1392
        ret
1393
 
1394
    .error:
1395
        mov     eax, ERROR_ACCESS_DENIED
1396
        jmp     .success
1397
 
1398
    .error_access_denied_delete:
1399
        popad
1400
 
1401
    .error_access_denied:
1402
        popad
1403
        xor     ebx, ebx
1404
 
1405
        mov     eax, ERROR_ACCESS_DENIED
1406
        jmp     .return
1407
 
1408
    .error_full:
1409
        popad
1410
        xor     ebx, ebx
1411
 
1412
        mov     eax, ERROR_DISK_FULL
1413
        jmp     .return
1414
 
1415
;---------------------------------------------------------------------
1416
; Write to a file.
1417
; Input:        esi + [esp + 4] = file name.
1418
;               ebx = pointer to paramteres from sysfunc 70.
1419
;               ebp = pointer to EXTFS structure.
1420
; Output:       eax = error code.
1421
;               ebx = number of bytes written.
1422
;---------------------------------------------------------------------
3935 shikhin 1423
ext2_Write:
4066 shikhin 1424
        ;DEBUGF 1, "Attempting write, "
1425
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1426
        jz      @F
1427
 
1428
        mov     eax, ERROR_UNSUPPORTED_FS
1429
        ret
1430
 
1431
    @@:
1432
        push    ecx edx esi edi
1433
        call    ext2_lock
1434
 
1435
        add     esi, [esp + 16 + 4]
1436
 
1437
        ; Can't write to root.
1438
        cmp     byte [esi], 0
1439
        jz      .error
1440
 
1441
        push    ebx ecx edx
1442
        stdcall ext2_inode_find, 0
1443
        pop     edx ecx ebx
1444
        ; If file not there, error.
1445
        xor     ecx, ecx
1446
        test    eax, eax
1447
        jnz     .error_file_not_found
1448
 
1449
        ; Save the inode.
1450
        push    esi
1451
 
1452
        ; Check if it's a file.
1453
        mov     edx, [ebp + EXTFS.ext2_save_inode]
1454
        cmp     [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
1455
        jne     .error
1456
 
1457
        mov     eax, esi
1458
        mov     ecx, [ebx + 4]
1459
 
1460
        call    ext2_inode_extend
1461
        xor     ecx, ecx
1462
        test    eax, eax
1463
        jnz     .error_device
1464
 
1465
        ; ECX contains the size to write, and ESI points to it.
1466
        mov     ecx, [ebx + 0x0C]
1467
        mov     esi, [ebx + 0x10]
1468
 
1469
        ; Save the size of the inode.
1470
        mov     eax, [edx + EXT2_INODE_STRUC.i_size]
1471
        push    eax
1472
 
1473
        xor     edx, edx
1474
        div     [ebp + EXTFS.block_size]
1475
 
1476
        test    edx, edx
1477
        jz      .start_aligned
1478
 
1479
        ; Start isn't aligned, so deal with the non-aligned bytes.
1480
        mov     ebx, [ebp + EXTFS.block_size]
1481
        sub     ebx, edx
1482
 
1483
        cmp     ebx, ecx
1484
        jbe     @F
1485
 
1486
        ; If the size to copy fits in current block, limit to that, instead of the entire block.
1487
        mov     ebx, ecx
1488
 
1489
    @@:
1490
        ; Copy EBX bytes, in EAX indexed block.
1491
        push    eax
1492
        call    ext2_inode_read_entry
1493
        test    eax, eax
1494
        pop     eax
1495
        jnz     .error_inode_size
1496
 
1497
        push    ecx
1498
 
1499
        mov     ecx, ebx
1500
        mov     edi, ebx
1501
        add     edi, edx
1502
        rep movsb
1503
 
1504
        pop     ecx
1505
 
1506
        ; Write the block.
1507
        call    ext2_inode_write_entry
1508
        test    eax, eax
1509
        jnz     .error_inode_size
1510
 
1511
        add     [esp], ebx
1512
        sub     ecx, ebx
1513
        jz      .write_inode
1514
 
1515
    .start_aligned:
1516
        cmp     ecx, [ebp + EXTFS.block_size]
1517
        jb      @F
1518
 
1519
        mov     eax, [esp]
1520
        xor     edx, edx
1521
        div     [ebp + EXTFS.block_size]
1522
 
1523
        push    eax
1524
        mov     edx, [esp + 8]
1525
        call    ext2_inode_blank_entry
1526
        test    eax, eax
1527
        pop     eax
1528
        jnz     .error_inode_size
1529
 
1530
        push    ecx
1531
 
1532
        mov     ecx, [ebp + EXTFS.block_size]
1533
        mov     edi, [ebp + EXTFS.ext2_save_block]
1534
        rep movsb
1535
 
1536
        pop     ecx
1537
 
1538
        call    ext2_inode_write_entry
1539
        test    eax, eax
1540
        jnz     .error_inode_size
1541
 
1542
        mov     eax, [ebp + EXTFS.block_size]
1543
        sub     ecx, eax
1544
        add     [esp], eax
1545
        jmp     .start_aligned
1546
 
1547
    ; Handle the remaining bytes.
1548
    @@:
1549
        test    ecx, ecx
1550
        jz      .write_inode
1551
 
1552
        mov     eax, [esp]
1553
        xor     edx, edx
1554
        div     [ebp + EXTFS.block_size]
1555
 
1556
        push    eax
1557
        call    ext2_inode_read_entry
1558
        test    eax, eax
1559
        pop     eax
1560
        jz      @F
1561
 
1562
        push    eax
1563
        mov     edx, [esp + 8]
1564
 
1565
        call    ext2_inode_blank_entry
1566
        test    eax, eax
1567
        pop     eax
1568
        jnz     .error_inode_size
1569
 
1570
    @@:
1571
        push    ecx
1572
        mov     edi, [ebp + EXTFS.ext2_save_block]
1573
        rep movsb
1574
        pop     ecx
1575
 
1576
        call    ext2_inode_write_entry
1577
        test    eax, eax
1578
        jnz     .error_inode_size
1579
 
1580
        add     [esp], ecx
1581
        xor     ecx, ecx
1582
 
1583
    .write_inode:
1584
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1585
        pop     eax
1586
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1587
        mov     eax, [esp]
1588
 
1589
        call    ext2_inode_write
1590
        test    eax, eax
1591
        jnz     .error_device
1592
 
1593
    .success:
1594
        call    ext2_sb_update
1595
 
1596
        ; Sync the disk.
1597
        mov     esi, [ebp + PARTITION.Disk]
1598
        call    disk_sync                       ; eax contains error code, if any.
1599
 
1600
    .return:
1601
        push    eax
1602
        call    ext2_unlock
1603
        pop     eax
1604
 
1605
        add     esp, 4
1606
 
1607
        mov     ebx, [esp + 12]
1608
        sub     ebx, ecx
1609
        pop     edi esi edx ecx
1610
 
1611
        ;DEBUGF  1, "and returning with: %x.\n", eax
1612
        ret
1613
 
1614
    .error:
1615
        mov     eax, ERROR_ACCESS_DENIED
1616
        jmp     .return
1617
 
1618
    .error_file_not_found:
1619
        mov     eax, ERROR_FILE_NOT_FOUND
1620
        jmp     .return
1621
 
1622
    .error_inode_size:
1623
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1624
        pop     eax
1625
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1626
        mov     eax, [esp]
1627
 
1628
        call    ext2_inode_write
1629
 
1630
    .error_device:
1631
        call    ext2_sb_update
1632
 
1633
        ; Sync the disk.
1634
        mov     esi, [ebp + PARTITION.Disk]
1635
        call    disk_sync                       ; eax contains error code, if any.
1636
 
1637
        mov     eax, ERROR_DEVICE
1638
        jmp     .return
1639
 
1640
;---------------------------------------------------------------------
1641
; Set the end of a file.
1642
; Input:        esi + [esp + 4] = file name.
1643
;               ebx = pointer to paramteres from sysfunc 70.
1644
;               ebp = pointer to EXTFS structure.
1645
; Output:       eax = error code.
1646
;---------------------------------------------------------------------
3935 shikhin 1647
ext2_SetFileEnd:
4066 shikhin 1648
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1649
        jz      @F
1650
 
3935 shikhin 1651
        mov     eax, ERROR_UNSUPPORTED_FS
1652
        ret
4066 shikhin 1653
 
1654
    @@:
1655
        push    ebx ecx edx esi edi
1656
        call    ext2_lock
1657
 
1658
        add     esi, [esp + 20 + 4]
1659
 
1660
        ; Can't write to root.
1661
        cmp     byte [esi], 0
1662
        jz      .error
1663
 
1664
        stdcall ext2_inode_find, 0
1665
        ; If file not there, error.
1666
        test    eax, eax
1667
        jnz     .error_file_not_found
1668
 
1669
        ; Check if it's a file.
1670
        mov     edx, [ebp + EXTFS.ext2_save_inode]
1671
        cmp     [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
1672
        jne     .error
1673
 
1674
        mov     eax, esi
1675
        mov     ecx, [ebx + 4]
1676
        call    ext2_inode_extend
1677
        test    eax, eax
1678
        jnz     .error_disk_full
1679
 
1680
        mov     eax, esi
1681
        call    ext2_inode_truncate
1682
        test    eax, eax
1683
        jnz     .error_disk_full
1684
 
1685
        mov     eax, esi
1686
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1687
        call    ext2_inode_write
1688
 
1689
        call    ext2_sb_update
1690
 
1691
        ; Sync the disk.
1692
        mov     esi, [ebp + PARTITION.Disk]
1693
        call    disk_sync                       ; eax contains error code, if any.
1694
 
1695
    .return:
1696
        push    eax
1697
        call    ext2_unlock
1698
        pop     eax
1699
 
1700
        pop     edi esi edx ecx ebx
1701
        ret
1702
 
1703
    .error:
1704
        mov     eax, ERROR_ACCESS_DENIED
1705
        jmp     .return
1706
 
1707
    .error_file_not_found:
1708
        mov     eax, ERROR_FILE_NOT_FOUND
1709
        jmp     .return
1710
 
1711
    .error_disk_full:
1712
        call    ext2_sb_update
1713
 
1714
        ; Sync the disk.
1715
        mov     esi, [ebp + PARTITION.Disk]
1716
        call    disk_sync                       ; eax contains error code, if any.
1717
 
1718
        mov     eax, ERROR_DISK_FULL
1719
        jmp     .return