Subversion Repositories Kolibri OS

Rev

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