Subversion Repositories Kolibri OS

Rev

Rev 4923 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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