Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4265 Serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Contains ext2 initialization, plus syscall handling code.    ;;
4
;;                                                              ;;
5
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
6
;; Distributed under the terms of the new BSD license.          ;;
7
;;                                                              ;;
8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9
 
10
include 'ext2.inc'
11
include 'blocks.inc'
12
include 'inode.inc'
13
include 'resource.inc'
14
 
15
iglobal
16
align 4
17
ext2_user_functions:
18
        dd      ext2_free
19
        dd      (ext2_user_functions_end - ext2_user_functions - 4) / 4
20
        dd      ext2_Read
21
        dd      ext2_ReadFolder
22
        dd      ext2_Rewrite
23
        dd      ext2_Write
24
        dd      ext2_SetFileEnd
25
        dd      ext2_GetFileInfo
26
        dd      ext2_SetFileInfo
27
        dd      0
28
        dd      ext2_Delete
29
        dd      ext2_CreateFolder
30
ext2_user_functions_end:
31
endg
32
 
33
;---------------------------------------------------------------------
34
; Locks up an ext2 partition.
35
; Input:        ebp = pointer to EXTFS.
36
;---------------------------------------------------------------------
37
proc ext2_lock
38
        lea     ecx, [ebp + EXTFS.lock]
39
        jmp     mutex_lock
40
endp
41
 
42
;---------------------------------------------------------------------
43
; Unlocks up an ext2 partition.
44
; Input:        ebp = pointer to EXTFS.
45
;---------------------------------------------------------------------
46
proc ext2_unlock
47
        lea     ecx, [ebp + EXTFS.lock]
48
        jmp     mutex_unlock
49
endp
50
 
51
;---------------------------------------------------------------------
52
; Check if it's a valid ext* superblock.
53
; Input:        ebp:       first three fields of PARTITION structure.
54
;               ebx + 512: points to 512-bytes buffer that can be used for anything.
55
; Output:       eax:       clear if can't create partition; set to EXTFS otherwise.
56
;---------------------------------------------------------------------
57
proc ext2_create_partition
58
        push    ebx
59
 
60
        mov     eax, 2                          ; Superblock starts at 1024-bytes.
61
        add     ebx, 512                        ; Get pointer to fs-specific buffer.
62
        call    fs_read32_sys
63
        test    eax, eax
64
        jnz     .fail
65
 
66
        ; Allowed 1KiB, 2KiB, 4KiB, 8KiB.
67
        cmp     [ebx + EXT2_SB_STRUC.log_block_size], 3
68
        ja      .fail
69
 
70
        cmp     [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC
71
        jne     .fail
72
 
73
        cmp     [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS
74
        jne     .fail
75
 
76
        ; Can't have no inodes per group.
77
        cmp     [ebx + EXT2_SB_STRUC.inodes_per_group], 0
78
        je      .fail
79
 
80
        ; If incompatible features required, unusable superblock.
81
        mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
82
        test    eax, not EXT4_FEATURE_INCOMPAT_SUPP
83
        jz      .setup
84
 
85
    .fail:
86
        ; Not a (valid/usable) EXT2 superblock.
87
        pop     ebx
88
        xor     eax, eax
89
        ret
90
 
91
    .setup:
92
        movi    eax, sizeof.EXTFS
93
        call    malloc
94
        test    eax, eax
95
        jz      ext2_create_partition.fail
96
 
97
        ; Store the first sector field.
98
        mov     ecx, dword[ebp + PARTITION.FirstSector]
99
        mov     dword[eax + EXTFS.FirstSector], ecx
100
        mov     ecx, dword [ebp + PARTITION.FirstSector+4]
101
        mov     dword [eax + EXTFS.FirstSector+4], ecx
102
 
103
        ; The length field.
104
        mov     ecx, dword[ebp + PARTITION.Length]
105
        mov     dword[eax + EXTFS.Length], ecx
106
        mov     ecx, dword[ebp + PARTITION.Length+4]
107
        mov     dword[eax + EXTFS.Length+4], ecx
108
 
109
        ; The disk field.
110
        mov     ecx, [ebp + PARTITION.Disk]
111
        mov     [eax + EXTFS.Disk], ecx
112
 
113
        mov     [eax + EXTFS.FSUserFunctions], ext2_user_functions
114
 
115
        push    ebp esi edi
116
 
117
        mov     ebp, eax
118
        lea     ecx, [eax + EXTFS.lock]
119
        call    mutex_init
120
 
121
        ; Copy superblock from buffer to reserved memory.
122
        mov     esi, ebx
123
        lea     edi, [ebp + EXTFS.superblock]
124
        mov     ecx, 512/4
125
        rep movsd
126
 
127
        ; Get total groups.
128
        mov     eax, [ebx + EXT2_SB_STRUC.blocks_count]
129
        sub     eax, [ebx + EXT2_SB_STRUC.first_data_block]
130
        dec     eax
131
        xor     edx, edx
132
        div     [ebx + EXT2_SB_STRUC.blocks_per_group]
133
        inc     eax
134
        mov     [ebp + EXTFS.groups_count], eax
135
 
136
        ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB.
137
        mov     ecx, [ebx + EXT2_SB_STRUC.log_block_size]
138
        inc     ecx
139
        mov     [ebp + EXTFS.log_block_size], ecx
140
 
141
        ; 512-byte blocks in ext2 blocks.
142
        mov     eax, 1
143
        shl     eax, cl
144
        mov     [ebp + EXTFS.count_block_in_block], eax
145
 
146
        ; Get block_size/4 (we'll find square later).
147
        shl     eax, 7
148
        mov     [ebp + EXTFS.count_pointer_in_block], eax
149
        mov     edx, eax
150
 
151
        ; Get block size.
152
        shl     eax, 2
153
        mov     [ebp + EXTFS.block_size], eax
154
 
155
        ; Save block size for 2 kernel_alloc calls.
156
        push    eax eax
157
 
158
        mov     eax, edx
159
        mul     edx
160
        mov     [ebp + EXTFS.count_pointer_in_block_square], eax
161
 
162
        ; Have temporary block storage for get_inode procedure, and one for global procedure.
163
        KERNEL_ALLOC [ebp + EXTFS.ext2_save_block], .error
164
        KERNEL_ALLOC [ebp + EXTFS.ext2_temp_block], .error
165
 
166
        mov     [ebp + EXTFS.partition_flags], 0x00000000
167
        mov     eax, [ebx + EXT2_SB_STRUC.feature_ro_compat]
168
        and     eax, not EXT2_FEATURE_RO_COMPAT_SUPP
169
        jnz     .read_only
170
 
171
        mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
172
        and     eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP
173
        jz      @F
174
 
175
    .read_only:
176
        ; Mark as read-only.
177
        or      [ebp + EXTFS.partition_flags], EXT2_RO
178
    @@:
179
        mov     ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
180
        mov     [ebp + EXTFS.blocks_per_group], ecx
181
 
182
        movzx   ecx, word[ebx + EXT2_SB_STRUC.inode_size]
183
        mov     [ebp + EXTFS.inode_size], ecx
184
 
185
        ; Allocate for three inodes (loop would be overkill).
186
        push    ecx ecx ecx
187
 
188
        KERNEL_ALLOC [ebp + EXTFS.ext2_save_inode], .error
189
        KERNEL_ALLOC [ebp + EXTFS.ext2_temp_inode], .error
190
        KERNEL_ALLOC [ebp + EXTFS.root_inode], .error
191
 
192
        ; Read root inode.
193
        mov     ebx, eax
194
        mov     eax, EXT2_ROOT_INO
195
        call    ext2_inode_read
196
 
197
        test    eax, eax
198
        jnz     .error
199
 
200
        ;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
 
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:
260
        ;DEBUGF  1, "Reading folder.\n"
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.
315
        call    ext2_inode_get_block
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]
364
        call    ext2_inode_get_block
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
491
 
492
        ;DEBUGF  1, "Returning with: %x.\n", eax
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
508
        ;DEBUGF  1, "Returning with: %x.\n", eax
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:
529
        ;DEBUGF  1, "Attempting read.\n"
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
619
        call    ext2_inode_get_block
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]
663
        call    ext2_inode_get_block
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
686
        call    ext2_inode_get_block
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
717
        ;DEBUGF  1, "Returning with: %x.\n", eax
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
735
 
736
        ;DEBUGF  1, "Returning with: %x.\n", eax
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:
747
        ;DEBUGF  1, "Calling for file info, for: %s.\n", esi
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
765
        ;DEBUGF  1, "Returning with: %x.\n", eax
766
        ret
767
 
768
    .is_root:
769
        xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
770
        mov     esi, [ebp + EXTFS.root_inode]
771
 
772
    @@:
773
        xor     eax, eax
774
        mov     edi, edx
775
        mov     ecx, 40/4
776
        rep stosd                                       ; Zero fill buffer.
777
 
778
        cmp     bl, '.'
779
        jne     @F
780
        or      dword [edx], FS_FT_HIDDEN
781
 
782
    @@:
783
        test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
784
        jnz     @F                                      ; If a directory, don't put in file size.
785
 
786
        mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
787
        mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
788
        mov     dword [edx+32], eax
789
        mov     dword [edx+36], ebx
790
 
791
        xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
792
    @@:
793
        xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
794
 
795
        lea     edi, [edx + 8]
796
 
797
        ; Store all time.
798
        mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
799
        xor     edx, edx
800
        add     eax, 3054539008
801
        adc     edx, 2
802
        call    ntfs_datetime_to_bdfe.sec
803
 
804
        mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
805
        xor     edx, edx
806
        add     eax, 3054539008
807
        adc     edx, 2
808
        call    ntfs_datetime_to_bdfe.sec
809
 
810
        mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
811
        xor     edx, edx
812
        add     eax, 3054539008
813
        adc     edx, 2
814
        call    ntfs_datetime_to_bdfe.sec
815
 
816
        call    ext2_unlock
817
        xor     eax, eax
818
        ;DEBUGF  1, "Returning with: %x.\n", eax
819
        ret
820
 
821
;---------------------------------------------------------------------
822
; Set file information for block device.
823
; Input:        esi + [esp + 4] = file name.
824
;               ebx = pointer to paramteres from sysfunc 70.
825
;               ebp = pointer to EXTFS structure.
826
; Output:       eax = error code.
827
;---------------------------------------------------------------------
828
ext2_SetFileInfo:
829
        test    [ebp + EXTFS.partition_flags], EXT2_RO
830
        jz      @F
831
 
832
        mov     eax, ERROR_UNSUPPORTED_FS
833
        ret
834
 
835
    @@:
836
        push    edx esi edi ebx
837
        call    ext2_lock
838
        mov     edx, [ebx + 16]
839
 
840
        ; Is this read-only?
841
        test    [ebp + EXTFS.partition_flags], EXT2_RO
842
        jnz     .fail
843
 
844
        ; Not supported for root.
845
        cmp     byte [esi], 0
846
        je      .fail
847
 
848
    .get_inode:
849
        push    edx
850
        stdcall ext2_inode_find, [esp + 4 + 20]
851
        pop     edx
852
 
853
        test    eax, eax
854
        jnz     @F
855
 
856
        ; Save inode number.
857
        push    esi
858
        mov     esi, [ebp + EXTFS.ext2_save_inode]
859
 
860
        ; From the BDFE, we ignore read-only file flags, hidden file flags;
861
        ; We ignore system file flags, file was archived or not.
862
 
863
        ; Also ignored is file creation time. ext2 stores "inode modification"
864
        ; time in the ctime field, which is updated by the respective inode_write
865
        ; procedure, and any writes on it would be overwritten anyway.
866
 
867
        ; Access time.
868
        lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
869
        lea     esi, [edx + 16]
870
        call    bdfe_to_unix_time
871
 
872
        ; Modification time.
873
        add     esi, 8
874
        add     edi, 8
875
        call    bdfe_to_unix_time
876
 
877
        mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
878
        pop     eax                             ; Get inode number in eax.
879
        call    ext2_inode_write                ; eax contains error code, if any.
880
        test    eax, eax
881
        jnz     @F
882
 
883
        call    ext2_sb_update
884
        ; Sync the disk.
885
        mov     esi, [ebp + PARTITION.Disk]
886
        call    disk_sync                       ; eax contains error code, if any.
887
 
888
    @@:
889
        push    eax
890
        call    ext2_unlock
891
        pop     eax
892
 
893
        pop     ebx edi esi edx
894
        ret
895
 
896
    .fail:
897
        call    ext2_sb_update
898
        ; Sync the disk.
899
        mov     esi, [ebp + PARTITION.Disk]
900
        call    disk_sync                       ; eax contains error code, if any.
901
 
902
        mov     eax, ERROR_UNSUPPORTED_FS
903
        jmp     @B
904
 
905
;---------------------------------------------------------------------
906
; Set file information for block device.
907
; Input:        esi + [esp + 4] = file name.
908
;               ebx = pointer to paramteres from sysfunc 70.
909
;               ebp = pointer to EXTFS structure.
910
; Output:       eax = error code.
911
;---------------------------------------------------------------------
912
ext2_Delete:
913
        ;DEBUGF  1, "Attempting Delete.\n"
914
        test    [ebp + EXTFS.partition_flags], EXT2_RO
915
        jz      @F
916
 
917
        mov     eax, ERROR_UNSUPPORTED_FS
918
        ret
919
 
920
    @@:
921
        push    ebx ecx edx esi edi
922
        call    ext2_lock
923
 
924
        add     esi, [esp + 20 + 4]
925
 
926
        ; Can't delete root.
927
        cmp     byte [esi], 0
928
        jz      .error_access_denied
929
 
930
        push    esi
931
        stdcall ext2_inode_find, 0
932
        mov     ebx, esi
933
        pop     esi
934
 
935
        test    eax, eax
936
        jnz     .error_access_denied
937
 
938
        mov     edx, [ebp + EXTFS.ext2_save_inode]
939
        movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
940
        and     edx, EXT2_S_IFMT                                ; Get the mask.
941
        cmp     edx, EXT2_S_IFDIR
942
        jne     @F                                              ; If not a directory, we don't need to check if it's empty.
943
 
944
        call    ext2_dir_empty                                  ; 0 means directory is empty.
945
 
946
        test    eax, eax
947
        jnz     .error_access_denied
948
 
949
    @@:
950
        ; Find parent.
951
        call    ext2_inode_find_parent
952
        test    eax, eax
953
        jnz     .error_access_denied
954
        mov     eax, esi
955
 
956
        ; Save file/dir & parent inode.
957
        push    ebx eax
958
 
959
        cmp     edx, EXT2_S_IFDIR
960
        jne     @F
961
 
962
        ; Unlink '.'
963
        mov     eax, [esp + 4]
964
        call    ext2_inode_unlink
965
        cmp     eax, 0xFFFFFFFF
966
        je      .error_stack8
967
 
968
        ; Unlink '..'
969
        mov     eax, [esp + 4]
970
        mov     ebx, [esp]
971
        call    ext2_inode_unlink
972
        cmp     eax, 0xFFFFFFFF
973
        je      .error_stack8
974
 
975
    @@:
976
        pop     eax
977
        mov     ebx, [esp]
978
        ; Unlink the inode.
979
        call    ext2_inode_unlink
980
        cmp     eax, 0xFFFFFFFF
981
        je      .error_stack4
982
 
983
        ; If hardlinks aren't zero, shouldn't completely free.
984
        test    eax, eax
985
        jz      @F
986
 
987
        add     esp, 4
988
        jmp     .disk_sync
989
 
990
    @@:
991
        ; Read the inode.
992
        mov     eax, [esp]
993
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
994
        call    ext2_inode_read
995
        test    eax, eax
996
        jnz     .error_stack4
997
 
998
        ; Free inode data.
999
        mov     esi, [ebp + EXTFS.ext2_save_inode]
1000
        xor     ecx, ecx
1001
 
1002
    @@:
1003
        push    ecx
1004
        call    ext2_inode_get_block
1005
        test    eax, eax
1006
        jnz     .error_stack8
1007
        mov     eax, ecx
1008
        pop     ecx
1009
 
1010
        ; If 0, we're done.
1011
        test    eax, eax
1012
        jz      @F
1013
 
1014
        call    ext2_block_free
1015
        test    eax, eax
1016
        jnz     .error_stack4
1017
 
1018
        inc     ecx
1019
        jmp     @B
1020
 
1021
    @@:
1022
        ; Free indirect blocks.
1023
        call    ext2_inode_free_indirect_blocks
1024
        test    eax, eax
1025
        jnz     .error_stack4
1026
 
1027
        ; Clear the inode, and add deletion time.
1028
        mov     edi, [ebp + EXTFS.ext2_save_inode]
1029
        xor     eax, eax
1030
        mov     ecx, [ebp + EXTFS.inode_size]
1031
        rep stosb
1032
 
1033
        mov     edi, [ebp + EXTFS.ext2_save_inode]
1034
        add     edi, EXT2_INODE_STRUC.i_dtime
1035
        call    current_unix_time
1036
 
1037
        ; Write the inode.
1038
        mov     eax, [esp]
1039
        mov     ebx, [ebp + EXTFS.ext2_save_inode]
1040
        call    ext2_inode_write
1041
        test    eax, eax
1042
        jnz     .error_stack4
1043
 
1044
        ; Check if directory.
1045
        cmp     edx, EXT2_S_IFDIR
1046
        jne     @F
1047
 
1048
        ; If it is, decrement used_dirs_count.
1049
 
1050
        ; Get block group.
1051
        mov     eax, [esp]
1052
        dec     eax
1053
        xor     edx, edx
1054
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1055
 
1056
        push    eax
1057
        call    ext2_bg_read_desc
1058
        test    eax, eax
1059
        jz      .error_stack8
1060
 
1061
        dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1062
 
1063
        pop     eax
1064
        call    ext2_bg_write_desc
1065
 
1066
    @@:
1067
        pop     eax
1068
        call    ext2_inode_free
1069
        test    eax, eax
1070
        jnz     .error_access_denied
1071
 
1072
    .disk_sync:
1073
        call    ext2_sb_update
1074
 
1075
        ; Sync the disk.
1076
        mov     esi, [ebp + PARTITION.Disk]
1077
        call    disk_sync                       ; eax contains error code, if any.
1078
 
1079
    .return:
1080
        push    eax
1081
        call    ext2_unlock
1082
        pop     eax
1083
 
1084
        pop     edi esi edx ecx ebx
1085
        ;DEBUGF  1, "And returning with: %x.\n", eax
1086
        ret
1087
 
1088
    .error_stack8:
1089
        add     esp, 4
1090
    .error_stack4:
1091
        add     esp, 4
1092
    .error_access_denied:
1093
        call    ext2_sb_update
1094
 
1095
        ; Sync the disk.
1096
        mov     esi, [ebp + PARTITION.Disk]
1097
        call    disk_sync                       ; eax contains error code, if any.
1098
 
1099
        mov     eax, ERROR_ACCESS_DENIED
1100
        jmp     .return
1101
 
1102
;---------------------------------------------------------------------
1103
; Set file information for block device.
1104
; Input:        esi + [esp + 4] = file name.
1105
;               ebx = pointer to paramteres from sysfunc 70.
1106
;               ebp = pointer to EXTFS structure.
1107
; Output:       eax = error code.
1108
;---------------------------------------------------------------------
1109
ext2_CreateFolder:
1110
        ;DEBUGF  1, "Attempting to create folder.\n"
1111
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1112
        jz      @F
1113
 
1114
        mov     eax, ERROR_UNSUPPORTED_FS
1115
        ret
1116
 
1117
    @@:
1118
        push    ebx ecx edx esi edi
1119
        call    ext2_lock
1120
 
1121
        add     esi, [esp + 20 + 4]
1122
 
1123
        ; Can't create root, but for CreateFolder already existing directory is success.
1124
        cmp     byte [esi], 0
1125
        jz      .success
1126
 
1127
        push    esi
1128
        stdcall ext2_inode_find, 0
1129
        pop     esi
1130
 
1131
        ; If the directory is there, we've succeeded.
1132
        test    eax, eax
1133
        jz      .success
1134
 
1135
        ; Find parent.
1136
        call    ext2_inode_find_parent
1137
        test    eax, eax
1138
        jnz     .error
1139
 
1140
        ; Inode ID for preference.
1141
        mov     eax, esi
1142
        call    ext2_inode_alloc
1143
        test    eax, eax
1144
        jnz     .error_full
1145
 
1146
        ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
1147
        mov     edx, ebx
1148
 
1149
        push    edi
1150
 
1151
        xor     al, al
1152
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1153
        mov     ecx, [ebp + EXTFS.inode_size]
1154
        rep stosb
1155
 
1156
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1157
        add     edi, EXT2_INODE_STRUC.i_atime
1158
        call    current_unix_time
1159
 
1160
        add     edi, 8
1161
        call    current_unix_time
1162
 
1163
        pop     edi
1164
 
1165
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1166
        mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR or PERMISSIONS
1167
        mov     eax, edx
1168
        call    ext2_inode_write
1169
        test    eax, eax
1170
        jnz     .error
1171
 
1172
        ; Link to self.
1173
        push    edx esi
1174
 
1175
        mov     eax, edx
1176
        mov     ebx, eax
1177
        mov     dl, EXT2_FT_DIR
1178
        mov     esi, self_link
1179
        call    ext2_inode_link
1180
 
1181
        pop     esi edx
1182
 
1183
        test    eax, eax
1184
        jnz     .error
1185
 
1186
        ; Link to parent.
1187
        push    edx esi
1188
 
1189
        mov     eax, ebx
1190
        mov     ebx, esi
1191
        mov     dl, EXT2_FT_DIR
1192
        mov     esi, parent_link
1193
        call    ext2_inode_link
1194
 
1195
        pop     esi edx
1196
 
1197
        test    eax, eax
1198
        jnz     .error
1199
 
1200
        ; Link parent to child.
1201
        mov     eax, esi
1202
        mov     ebx, edx
1203
        mov     esi, edi
1204
        mov     dl, EXT2_FT_DIR
1205
        call    ext2_inode_link
1206
        test    eax, eax
1207
        jnz     .error
1208
 
1209
        ; Get block group descriptor for allocated inode's block.
1210
        mov     eax, ebx
1211
        dec     eax
1212
        xor     edx, edx
1213
 
1214
        ; EAX = block group.
1215
        div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
1216
        mov     edx, eax
1217
 
1218
        call    ext2_bg_read_desc
1219
        test    eax, eax
1220
        jz      .error
1221
 
1222
        inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
1223
        mov     eax, edx
1224
        call    ext2_bg_write_desc
1225
        test    eax, eax
1226
        jnz     .error
1227
 
1228
    .success:
1229
        call    ext2_sb_update
1230
 
1231
        ; Sync the disk.
1232
        mov     esi, [ebp + PARTITION.Disk]
1233
        call    disk_sync                       ; eax contains error code, if any.
1234
 
1235
    .return:
1236
        push    eax
1237
        call    ext2_unlock
1238
        pop     eax
1239
 
1240
        pop     edi esi edx ecx ebx
1241
        ;DEBUGF  1, "Returning with: %x.\n", eax
1242
        ret
1243
 
1244
    .error:
1245
        call    ext2_sb_update
1246
 
1247
        ; Sync the disk.
1248
        mov     esi, [ebp + PARTITION.Disk]
1249
        call    disk_sync                       ; eax contains error code, if any.
1250
 
1251
        mov     eax, ERROR_ACCESS_DENIED
1252
        jmp     .return
1253
 
1254
    .error_full:
1255
        mov     eax, ERROR_DISK_FULL
1256
        jmp     .return
1257
 
1258
self_link   db ".", 0
1259
parent_link db "..", 0
1260
 
1261
;---------------------------------------------------------------------
1262
; Rewrite a file.
1263
; Input:        esi + [esp + 4] = file name.
1264
;               ebx = pointer to paramteres from sysfunc 70.
1265
;               ebp = pointer to EXTFS structure.
1266
; Output:       eax = error code.
1267
;               ebx = bytes written.
1268
;---------------------------------------------------------------------
1269
ext2_Rewrite:
1270
        ;DEBUGF  1, "Attempting Rewrite.\n"
1271
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1272
        jz      @F
1273
 
1274
        mov     eax, ERROR_UNSUPPORTED_FS
1275
        ret
1276
 
1277
    @@:
1278
        push    ecx edx esi edi
1279
        pushad
1280
 
1281
        call    ext2_lock
1282
 
1283
        add     esi, [esp + 16 + 32 + 4]
1284
        ; Can't create root.
1285
        cmp     byte [esi], 0
1286
        jz      .error_access_denied
1287
 
1288
        push    esi
1289
        stdcall ext2_inode_find, 0
1290
        pop     esi
1291
 
1292
        ; If the file is there, delete it.
1293
        test    eax, eax
1294
        jnz     @F
1295
 
1296
        pushad
1297
 
1298
        push    eax
1299
        call    ext2_unlock
1300
        pop     eax
1301
 
1302
        push    dword 0x00000000
1303
        call    ext2_Delete
1304
        add     esp, 4
1305
 
1306
        push    eax
1307
        call    ext2_lock
1308
        pop     eax
1309
 
1310
        test    eax, eax
1311
        jnz     .error_access_denied_delete
1312
 
1313
        popad
1314
    @@:
1315
        ; Find parent.
1316
        call    ext2_inode_find_parent
1317
        test    eax, eax
1318
        jnz     .error_access_denied
1319
 
1320
        ; Inode ID for preference.
1321
        mov     eax, esi
1322
        call    ext2_inode_alloc
1323
        test    eax, eax
1324
        jnz     .error_full
1325
 
1326
        ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
1327
        mov     edx, ebx
1328
 
1329
        push    edi
1330
 
1331
        xor     al, al
1332
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1333
        mov     ecx, [ebp + EXTFS.inode_size]
1334
        rep stosb
1335
 
1336
        mov     edi, [ebp + EXTFS.ext2_temp_inode]
1337
        add     edi, EXT2_INODE_STRUC.i_atime
1338
        call    current_unix_time
1339
 
1340
        add     edi, 8
1341
        call    current_unix_time
1342
 
1343
        pop     edi
1344
 
1345
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1346
        mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG or PERMISSIONS
1347
        mov     eax, edx
1348
        call    ext2_inode_write
1349
        test    eax, eax
1350
        jnz     .error
1351
 
1352
        ; Link parent to child.
1353
        mov     eax, esi
1354
        mov     ebx, edx
1355
        mov     esi, edi
1356
        mov     dl, EXT2_FT_REG_FILE
1357
        call    ext2_inode_link
1358
        test    eax, eax
1359
        jnz     .error
1360
 
1361
        popad
1362
        push    eax
1363
        call    ext2_unlock
1364
        pop     eax
1365
 
1366
        push    dword 0x00000000
1367
        call    ext2_Write
1368
        add     esp, 4
1369
 
1370
        push    eax
1371
        call    ext2_lock
1372
        pop     eax
1373
 
1374
    .success:
1375
        push    eax
1376
        call    ext2_sb_update
1377
 
1378
        ; Sync the disk.
1379
        mov     esi, [ebp + PARTITION.Disk]
1380
        call    disk_sync                       ; eax contains error code, if any.
1381
        pop     eax
1382
 
1383
    .return:
1384
        push    eax
1385
        call    ext2_unlock
1386
        pop     eax
1387
 
1388
        pop     edi esi edx ecx
1389
 
1390
        ;DEBUGF  1, "And returning with: %x.\n", eax
1391
        ret
1392
 
1393
    .error:
1394
        mov     eax, ERROR_ACCESS_DENIED
1395
        jmp     .success
1396
 
1397
    .error_access_denied_delete:
1398
        popad
1399
 
1400
    .error_access_denied:
1401
        popad
1402
        xor     ebx, ebx
1403
 
1404
        mov     eax, ERROR_ACCESS_DENIED
1405
        jmp     .return
1406
 
1407
    .error_full:
1408
        popad
1409
        xor     ebx, ebx
1410
 
1411
        mov     eax, ERROR_DISK_FULL
1412
        jmp     .return
1413
 
1414
;---------------------------------------------------------------------
1415
; Write to a file.
1416
; Input:        esi + [esp + 4] = file name.
1417
;               ebx = pointer to paramteres from sysfunc 70.
1418
;               ebp = pointer to EXTFS structure.
1419
; Output:       eax = error code.
1420
;               ebx = number of bytes written.
1421
;---------------------------------------------------------------------
1422
ext2_Write:
1423
        ;DEBUGF 1, "Attempting write, "
1424
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1425
        jz      @F
1426
 
1427
        mov     eax, ERROR_UNSUPPORTED_FS
1428
        ret
1429
 
1430
    @@:
1431
        push    ecx edx esi edi
1432
        call    ext2_lock
1433
 
1434
        add     esi, [esp + 16 + 4]
1435
 
1436
        ; Can't write to root.
1437
        cmp     byte [esi], 0
1438
        jz      .error
1439
 
1440
        push    ebx ecx edx
1441
        stdcall ext2_inode_find, 0
1442
        pop     edx ecx ebx
1443
        ; If file not there, error.
1444
        xor     ecx, ecx
1445
        test    eax, eax
1446
        jnz     .error_file_not_found
1447
 
1448
        ; Save the inode.
1449
        push    esi
1450
 
1451
        ; Check if it's a file.
1452
        mov     edx, [ebp + EXTFS.ext2_save_inode]
1453
        test    [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
1454
        jz      .error
1455
 
1456
        mov     eax, esi
1457
        mov     ecx, [ebx + 4]
1458
 
1459
        call    ext2_inode_extend
1460
        xor     ecx, ecx
1461
        test    eax, eax
1462
        jnz     .error_device
1463
 
1464
        ; ECX contains the size to write, and ESI points to it.
1465
        mov     ecx, [ebx + 0x0C]
1466
        mov     esi, [ebx + 0x10]
1467
 
1468
        ; Save the size of the inode.
1469
        mov     eax, [edx + EXT2_INODE_STRUC.i_size]
1470
        push    eax
1471
 
1472
        xor     edx, edx
1473
        div     [ebp + EXTFS.block_size]
1474
 
1475
        test    edx, edx
1476
        jz      .start_aligned
1477
 
1478
        ; Start isn't aligned, so deal with the non-aligned bytes.
1479
        mov     ebx, [ebp + EXTFS.block_size]
1480
        sub     ebx, edx
1481
 
1482
        cmp     ebx, ecx
1483
        jbe     @F
1484
 
1485
        ; If the size to copy fits in current block, limit to that, instead of the entire block.
1486
        mov     ebx, ecx
1487
 
1488
    @@:
1489
        ; Copy EBX bytes, in EAX indexed block.
1490
        push    eax
1491
        call    ext2_inode_read_entry
1492
        test    eax, eax
1493
        pop     eax
1494
        jnz     .error_inode_size
1495
 
1496
        push    ecx
1497
 
1498
        mov     ecx, ebx
1499
        mov     edi, ebx
1500
        add     edi, edx
1501
        rep movsb
1502
 
1503
        pop     ecx
1504
 
1505
        ; Write the block.
1506
        call    ext2_inode_write_entry
1507
        test    eax, eax
1508
        jnz     .error_inode_size
1509
 
1510
        add     [esp], ebx
1511
        sub     ecx, ebx
1512
        jz      .write_inode
1513
 
1514
    .start_aligned:
1515
        cmp     ecx, [ebp + EXTFS.block_size]
1516
        jb      @F
1517
 
1518
        mov     eax, [esp]
1519
        xor     edx, edx
1520
        div     [ebp + EXTFS.block_size]
1521
 
1522
        push    eax
1523
        mov     edx, [esp + 8]
1524
        call    ext2_inode_blank_entry
1525
        test    eax, eax
1526
        pop     eax
1527
        jnz     .error_inode_size
1528
 
1529
        push    ecx
1530
 
1531
        mov     ecx, [ebp + EXTFS.block_size]
1532
        mov     edi, [ebp + EXTFS.ext2_save_block]
1533
        rep movsb
1534
 
1535
        pop     ecx
1536
 
1537
        call    ext2_inode_write_entry
1538
        test    eax, eax
1539
        jnz     .error_inode_size
1540
 
1541
        mov     eax, [ebp + EXTFS.block_size]
1542
        sub     ecx, eax
1543
        add     [esp], eax
1544
        jmp     .start_aligned
1545
 
1546
    ; Handle the remaining bytes.
1547
    @@:
1548
        test    ecx, ecx
1549
        jz      .write_inode
1550
 
1551
        mov     eax, [esp]
1552
        xor     edx, edx
1553
        div     [ebp + EXTFS.block_size]
1554
 
1555
        push    eax
1556
        call    ext2_inode_read_entry
1557
        test    eax, eax
1558
        pop     eax
1559
        jz      @F
1560
 
1561
        push    eax
1562
        mov     edx, [esp + 8]
1563
 
1564
        call    ext2_inode_blank_entry
1565
        test    eax, eax
1566
        pop     eax
1567
        jnz     .error_inode_size
1568
 
1569
    @@:
1570
        push    ecx
1571
        mov     edi, [ebp + EXTFS.ext2_save_block]
1572
        rep movsb
1573
        pop     ecx
1574
 
1575
        call    ext2_inode_write_entry
1576
        test    eax, eax
1577
        jnz     .error_inode_size
1578
 
1579
        add     [esp], ecx
1580
        xor     ecx, ecx
1581
 
1582
    .write_inode:
1583
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1584
        pop     eax
1585
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1586
        mov     eax, [esp]
1587
 
1588
        call    ext2_inode_write
1589
        test    eax, eax
1590
        jnz     .error_device
1591
 
1592
    .success:
1593
        call    ext2_sb_update
1594
 
1595
        ; Sync the disk.
1596
        mov     esi, [ebp + PARTITION.Disk]
1597
        call    disk_sync                       ; eax contains error code, if any.
1598
 
1599
    .return:
1600
        push    eax
1601
        call    ext2_unlock
1602
        pop     eax
1603
 
1604
        add     esp, 4
1605
 
1606
        mov     ebx, [esp + 12]
1607
        sub     ebx, ecx
1608
        pop     edi esi edx ecx
1609
 
1610
        ;DEBUGF  1, "and returning with: %x.\n", eax
1611
        ret
1612
 
1613
    .error:
1614
        mov     eax, ERROR_ACCESS_DENIED
1615
        jmp     .return
1616
 
1617
    .error_file_not_found:
1618
        mov     eax, ERROR_FILE_NOT_FOUND
1619
        jmp     .return
1620
 
1621
    .error_inode_size:
1622
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1623
        pop     eax
1624
        mov     [ebx + EXT2_INODE_STRUC.i_size], eax
1625
        mov     eax, [esp]
1626
 
1627
        call    ext2_inode_write
1628
 
1629
    .error_device:
1630
        call    ext2_sb_update
1631
 
1632
        ; Sync the disk.
1633
        mov     esi, [ebp + PARTITION.Disk]
1634
        call    disk_sync                       ; eax contains error code, if any.
1635
 
1636
        mov     eax, ERROR_DEVICE
1637
        jmp     .return
1638
 
1639
;---------------------------------------------------------------------
1640
; Set the end of a file.
1641
; Input:        esi + [esp + 4] = file name.
1642
;               ebx = pointer to paramteres from sysfunc 70.
1643
;               ebp = pointer to EXTFS structure.
1644
; Output:       eax = error code.
1645
;---------------------------------------------------------------------
1646
ext2_SetFileEnd:
1647
        test    [ebp + EXTFS.partition_flags], EXT2_RO
1648
        jz      @F
1649
 
1650
        mov     eax, ERROR_UNSUPPORTED_FS
1651
        ret
1652
 
1653
    @@:
1654
        push    ebx ecx edx esi edi
1655
        call    ext2_lock
1656
 
1657
        add     esi, [esp + 20 + 4]
1658
 
1659
        ; Can't write to root.
1660
        cmp     byte [esi], 0
1661
        jz      .error
1662
 
1663
        stdcall ext2_inode_find, 0
1664
        ; If file not there, error.
1665
        test    eax, eax
1666
        jnz     .error_file_not_found
1667
 
1668
        ; Check if it's a file.
1669
        mov     edx, [ebp + EXTFS.ext2_save_inode]
1670
        cmp     [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
1671
        jne     .error
1672
 
1673
        mov     eax, esi
1674
        mov     ecx, [ebx + 4]
1675
        call    ext2_inode_extend
1676
        test    eax, eax
1677
        jnz     .error_disk_full
1678
 
1679
        mov     eax, esi
1680
        call    ext2_inode_truncate
1681
        test    eax, eax
1682
        jnz     .error_disk_full
1683
 
1684
        mov     eax, esi
1685
        mov     ebx, [ebp + EXTFS.ext2_temp_inode]
1686
        call    ext2_inode_write
1687
 
1688
        call    ext2_sb_update
1689
 
1690
        ; Sync the disk.
1691
        mov     esi, [ebp + PARTITION.Disk]
1692
        call    disk_sync                       ; eax contains error code, if any.
1693
 
1694
    .return:
1695
        push    eax
1696
        call    ext2_unlock
1697
        pop     eax
1698
 
1699
        pop     edi esi edx ecx ebx
1700
        ret
1701
 
1702
    .error:
1703
        mov     eax, ERROR_ACCESS_DENIED
1704
        jmp     .return
1705
 
1706
    .error_file_not_found:
1707
        mov     eax, ERROR_FILE_NOT_FOUND
1708
        jmp     .return
1709
 
1710
    .error_disk_full:
1711
        call    ext2_sb_update
1712
 
1713
        ; Sync the disk.
1714
        mov     esi, [ebp + PARTITION.Disk]
1715
        call    disk_sync                       ; eax contains error code, if any.
1716
 
1717
        mov     eax, ERROR_DISK_FULL
1718
        jmp     .return