Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
425 victor 1
$Revision: 465 $
431 serge 2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
465 serge 3
;;                                                                 ;;
431 serge 4
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
5
;; Distributed under terms of the GNU General Public License    ;;
6
;;                                                              ;;
465 serge 7
;;  FAT32.INC                                                      ;;
8
;;                                                                 ;;
9
;;  FAT16/32 functions for KolibriOS                               ;;
10
;;                                                                 ;;
11
;;  Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it          ;;
12
;;                                                                 ;;
13
;;  See file COPYING for details                                   ;;
14
;;  04.02.2007 LFN create folder - diamond                         ;;
15
;;  08.10.2006 LFN delete file/folder - diamond                    ;;
16
;;  20.08.2006 LFN set file size (truncate/extend) - diamond       ;;
17
;;  17.08.2006 LFN write/append to file - diamond                  ;;
18
;;  23.06.2006 LFN start application - diamond                     ;;
19
;;  15.06.2006 LFN get/set file/folder info - diamond              ;;
20
;;  27.05.2006 LFN create/rewrite file - diamond                   ;;
21
;;  04.05.2006 LFN read folder - diamond                           ;;
22
;;  29.04.2006 Elimination of hangup after the                     ;;
23
;;             expiration hd_wait_timeout -  Mario79               ;;
24
;;  23.04.2006 LFN read file - diamond                             ;;
25
;;  28.01.2006 find all Fat16/32 partition in all input point      ;;
26
;;             to MBR, see file part_set.inc - Mario79             ;;
27
;;  15.01.2005 get file size/attr/date, file_append - ATV          ;;
28
;;  04.12.2004 skip volume label, file delete bug fixed - ATV      ;;
29
;;  29.11.2004 get_free_FAT changed, append dir bug fixed - ATV    ;;
30
;;  23.11.2004 don't allow overwrite dir with file - ATV           ;;
31
;;  18.11.2004 get_disk_info and more error codes - ATV            ;;
32
;;  17.11.2004 set_FAT/get_FAT and disk cache rewritten - ATV      ;;
33
;;  10.11.2004 removedir clear whole directory structure - ATV     ;;
34
;;  08.11.2004 rename - ATV                                        ;;
35
;;  30.10.2004 file_read return also dirsize in bytes - ATV        ;;
36
;;  20.10.2004 Makedir/Removedir - ATV                             ;;
37
;;  14.10.2004 Partition chain/Fat16 - ATV (thanks drh3xx)         ;;
38
;;  06.9.2004  Fix free space by Mario79 added - MH                ;;
39
;;  24.5.2004  Write back buffer for File_write -VT                ;;
40
;;  20.5.2004  File_read function to work with syscall 58 - VT     ;;
41
;;  30.3.2004  Error parameters at function return - VT            ;;
42
;;  01.5.2002  Bugfix in device write - VT                         ;;
43
;;  20.5.2002  Hd status check - VT                                ;;
44
;;  29.6.2002  Improved fat32 verification - VT                    ;;
45
;;                                                                 ;;
431 serge 46
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1 ha 47
 
48
cache_max equ 1919      ; max. is 1919*512+0x610000=0x6ffe00
49
 
52 mikedld 50
ERROR_SUCCESS        = 0
51
ERROR_DISK_BASE      = 1
52
ERROR_UNSUPPORTED_FS = 2
53
ERROR_UNKNOWN_FS     = 3
54
ERROR_PARTITION      = 4
55
ERROR_FILE_NOT_FOUND = 5
56
ERROR_END_OF_FILE    = 6
57
ERROR_MEMORY_POINTER = 7
58
ERROR_DISK_FULL      = 8
59
ERROR_FAT_TABLE      = 9
60
ERROR_ACCESS_DENIED  = 10
1 ha 61
 
62
PUSHAD_EAX equ [esp+28]
63
PUSHAD_ECX equ [esp+24]
64
PUSHAD_EDX equ [esp+20]
65
PUSHAD_EBX equ [esp+16]
66
PUSHAD_EBP equ [esp+8]
67
PUSHAD_ESI equ [esp+4]
68
PUSHAD_EDI equ [esp+0]
69
 
171 diamond 70
uglobal
71
align 4
1 ha 72
cluster              dd 0       ; used by file_write,makedir,append
73
partition_count      dd 0       ; partitions found by set_FAT32_variables
74
longname_sec1        dd 0       ; used by analyze_directory to save 2 previous
75
longname_sec2        dd 0       ; directory sectors for delete long filename
76
 
77
hd_error             dd 0       ; set by wait_for_sector_buffer
78
hd_setup             dd 0
79
hd_wait_timeout      dd 0
80
 
81
cluster_tmp          dd 0       ; used by analyze_directory
82
                                ; and analyze_directory_to_write
83
 
84
file_size            dd 0       ; used by file_read
85
 
86
sector_tmp           dd 0       ; used by rename,append,file_write
87
entry_pos            dd 0       ; used by rename,append,file_write
88
 
89
old_filesize         dd 0       ; used by append
90
new_filepos          dd 0       ; used by append
91
bytes2write          dd 0       ; used by append
92
 
93
cache_search_start   dd 0       ; used by find_empty_slot
171 diamond 94
endg
1 ha 95
 
171 diamond 96
iglobal
1 ha 97
fat_in_cache         dd -1
171 diamond 98
endg
1 ha 99
 
100
uglobal
171 diamond 101
align 4
102
fat_cache:           times 512 db 0
1 ha 103
 Sector512:                      ; label for dev_hdcd.inc
104
  buffer:              times 512 db 0
133 diamond 105
  fsinfo_buffer:       times 512 db 0
1 ha 106
endg
107
 
108
uglobal
109
  dir_entry:           times 32 db 0
110
 
111
  startpath:           times 255 db 0
112
 
113
  fat16_root           db 0       ; flag for fat16 rootdir
114
  fat_change           db 0       ; 1=fat has changed
115
 
116
endg
117
 
118
reserve_hd1:
119
 
120
    cli
121
    cmp   [hd1_status],0
122
    je    reserve_ok1
123
 
124
    sti
125
    call  change_task
126
    jmp   reserve_hd1
127
 
128
  reserve_ok1:
129
 
130
    push  eax
379 serge 131
    mov   eax,[CURRENT_TASK]
1 ha 132
    shl   eax,5
379 serge 133
    mov   eax,[eax+CURRENT_TASK+TASKDATA.pid]
1 ha 134
    mov   [hd1_status],eax
135
    pop   eax
136
    sti
137
    ret
95 mario79 138
;********************************************
321 diamond 139
 
140
uglobal
141
hd_in_cache db ?
142
endg
143
 
95 mario79 144
reserve_hd_channel:
145
    cmp   [hdbase], 0x1F0
146
    jne   .IDE_Channel_2
147
.IDE_Channel_1:
148
    cli
149
    cmp   [IDE_Channel_1],0
150
    je    .reserve_ok_1
151
    sti
152
    call  change_task
153
    jmp   .IDE_Channel_1
154
.IDE_Channel_2:
155
    cli
156
    cmp   [IDE_Channel_2],0
157
    je    .reserve_ok_2
158
    sti
159
    call  change_task
321 diamond 160
    jmp   .IDE_Channel_2
95 mario79 161
.reserve_ok_1:
321 diamond 162
        mov     [IDE_Channel_1], 1
163
        push    eax
164
        mov     al, 1
165
        jmp     @f
95 mario79 166
.reserve_ok_2:
321 diamond 167
        mov     [IDE_Channel_2], 1
168
        push    eax
169
        mov     al, 3
170
@@:
171
        cmp     [hdid], 1
172
        sbb     al, -1
173
        cmp     al, [hd_in_cache]
174
        jz      @f
175
        mov     [hd_in_cache], al
176
        call    clear_hd_cache
177
@@:
178
	pop     eax
179
        ret
180
 
95 mario79 181
free_hd_channel:
182
    cmp   [hdbase], 0x1F0
183
    jne   .IDE_Channel_2
184
.IDE_Channel_1:
185
    mov [IDE_Channel_1],0
186
    ret
187
.IDE_Channel_2:
188
    mov [IDE_Channel_2],0
189
    ret
190
;********************************************
379 serge 191
problem_partition db 0  ; used for partitions search
1 ha 192
 
65 mario79 193
include  'part_set.inc'
1 ha 194
 
195
set_FAT:
196
;--------------------------------
197
; input  : EAX = cluster
198
;          EDX = value to save
199
; output : EDX = old value
200
;--------------------------------
201
    push  eax ebx esi
202
 
203
    cmp   eax,2
204
    jb    sfc_error
205
    cmp   eax,[LAST_CLUSTER]
206
    ja    sfc_error
256 diamond 207
    cmp   [fs_type],16
1 ha 208
    je    sfc_1
209
    add   eax,eax
210
  sfc_1:
211
    add   eax,eax
212
    mov   esi,511
213
    and   esi,eax               ; esi = position in fat sector
214
    shr   eax,9                 ; eax = fat sector
215
    add   eax,[FAT_START]
216
    mov   ebx,fat_cache
217
 
218
    cmp   eax,[fat_in_cache]    ; is fat sector already in memory?
219
    je    sfc_in_cache          ; yes
220
 
221
    cmp   [fat_change],0        ; is fat changed?
222
    je    sfc_no_change         ; no
223
    call  write_fat_sector      ; yes. write it into disk
74 mario79 224
    cmp   [hd_error],0
225
    jne   sfc_error
1 ha 226
 
227
  sfc_no_change:
228
    mov   [fat_in_cache],eax    ; save fat sector
229
    call  hd_read
74 mario79 230
    cmp  [hd_error],0
231
    jne  sfc_error
1 ha 232
 
379 serge 233
 
1 ha 234
  sfc_in_cache:
256 diamond 235
    cmp   [fs_type],16
1 ha 236
    jne   sfc_test32
237
 
238
  sfc_set16:
239
    xchg  [ebx+esi],dx          ; save new value and get old value
240
    jmp   sfc_write
241
 
242
  sfc_test32:
243
    mov   eax,[fatMASK]
244
 
245
  sfc_set32:
246
    and   edx,eax
247
    xor   eax,-1                ; mask for high bits
248
    and   eax,[ebx+esi]         ; get high 4 bits
249
    or    eax,edx
250
    mov   edx,[ebx+esi]         ; get old value
251
    mov   [ebx+esi],eax         ; save new value
252
 
253
  sfc_write:
254
    mov   [fat_change],1        ; fat has changed
255
 
256
  sfc_nonzero:
257
    and   edx,[fatMASK]
258
 
259
  sfc_error:
260
    pop   esi ebx eax
261
    ret
262
 
263
 
264
get_FAT:
265
;--------------------------------
266
; input  : EAX = cluster
267
; output : EAX = next cluster
268
;--------------------------------
269
    push  ebx esi
270
 
256 diamond 271
    cmp   [fs_type],16
1 ha 272
    je    gfc_1
273
    add   eax,eax
274
  gfc_1:
275
    add   eax,eax
276
    mov   esi,511
277
    and   esi,eax               ; esi = position in fat sector
278
    shr   eax,9                 ; eax = fat sector
279
    add   eax,[FAT_START]
280
    mov   ebx,fat_cache
281
 
282
    cmp   eax,[fat_in_cache]    ; is fat sector already in memory?
283
    je    gfc_in_cache
284
 
285
    cmp   [fat_change],0        ; is fat changed?
286
    je    gfc_no_change         ; no
287
    call  write_fat_sector      ; yes. write it into disk
74 mario79 288
    cmp  [hd_error],0
289
    jne  hd_error_01
1 ha 290
 
291
  gfc_no_change:
292
    mov   [fat_in_cache],eax
293
    call  hd_read
74 mario79 294
    cmp  [hd_error],0
295
    jne  hd_error_01
1 ha 296
 
297
  gfc_in_cache:
298
    mov   eax,[ebx+esi]
299
    and   eax,[fatMASK]
74 mario79 300
 hd_error_01:
1 ha 301
    pop   esi ebx
302
    ret
303
 
304
 
305
get_free_FAT:
306
;-----------------------------------------------------------
307
; input  : EAX = # cluster for start the searching
308
; output : if CARRY=0 EAX = # first cluster found free
309
;          if CARRY=1 disk full
310
; Note   : for more speed need to use fat_cache directly
311
;-----------------------------------------------------------
312
    push  ecx
313
    mov   ecx,[LAST_CLUSTER]    ; counter for full disk
314
    sub   ecx,2
315
 
316
  gff_test:
317
    cmp   eax,[LAST_CLUSTER]    ; if above last cluster start at cluster 2
318
    jbe   gff_in_range
319
    mov   eax,2
320
 
321
  gff_in_range:
322
    push  eax
323
    call  get_FAT               ; get cluster state
74 mario79 324
    cmp   [hd_error],0
325
    jne   gff_not_found_1
326
 
1 ha 327
    test  eax,eax               ; is it free?
328
    pop   eax
329
    je    gff_found             ; yes
330
    inc   eax                   ; next cluster
331
    dec   ecx                   ; is all checked?
332
    jns   gff_test              ; no
333
 
74 mario79 334
  gff_not_found_1:
335
    add   esp,4
1 ha 336
  gff_not_found:
337
    pop   ecx                   ; yes. disk is full
338
    stc
339
    ret
340
 
341
  gff_found:
342
    pop   ecx
343
    clc
344
    ret
345
 
346
 
347
write_fat_sector:
348
;-----------------------------------------------------------
349
; write changed fat to disk
350
;-----------------------------------------------------------
351
    push  eax ebx ecx
352
 
353
    mov   [fat_change],0
354
    mov   eax,[fat_in_cache]
355
    cmp   eax,-1
356
    jz    write_fat_not_used
357
    mov   ebx,fat_cache
358
    mov   ecx,[NUMBER_OF_FATS]
359
 
360
  write_next_fat:
361
    call  hd_write
74 mario79 362
    cmp   [hd_error],0
363
    jne   write_fat_not_used
364
 
1 ha 365
    add   eax,[SECTORS_PER_FAT]
366
    dec   ecx
367
    jnz   write_next_fat
368
 
369
  write_fat_not_used:
370
    pop   ecx ebx eax
371
    ret
372
 
373
 
374
analyze_directory:
375
;-----------------------------------------------------------
376
; input  : EAX = first cluster of the directory
377
;          EBX = pointer to filename
378
; output : IF CARRY=0 EAX = sector where th file is found
379
;                     EBX = pointer in buffer
380
;                     [buffer .. buffer+511]
381
;                     ECX,EDX,ESI,EDI not changed
382
;          IF CARRY=1 filename not found
383
; Note   : if cluster=0 it's changed to read rootdir
384
;          save 2 previous directory sectors in longname_sec
385
;-----------------------------------------------------------
386
    push  ecx edx esi edi ebx   ; ebx = [esp+0]
387
    mov   [longname_sec1],0
388
    mov   [longname_sec2],0
389
 
390
  adr_new_cluster:
391
    mov   [cluster_tmp],eax
392
    mov   [fat16_root],0
393
    cmp   eax,[LAST_CLUSTER]
394
    ja    adr_not_found         ; too big cluster number, something is wrong
395
    cmp   eax,2
396
    jnb   adr_data_cluster
397
 
398
    mov   eax,[ROOT_CLUSTER]    ; if cluster < 2 then read rootdir
256 diamond 399
    cmp   [fs_type],16
1 ha 400
    jne   adr_data_cluster
401
    mov   eax,[ROOT_START]
402
    mov   edx,[ROOT_SECTORS]
403
    mov   [fat16_root],1        ; flag for fat16 rootdir
404
    jmp   adr_new_sector
405
 
406
  adr_data_cluster:
407
    sub   eax,2
408
    mov   edx,[SECTORS_PER_CLUSTER]
409
    imul  eax,edx
410
    add   eax,[DATA_START]
411
 
412
  adr_new_sector:
413
    mov   ebx,buffer
414
    call  hd_read
74 mario79 415
    cmp  [hd_error],0
416
    jne  adr_not_found
417
 
1 ha 418
    mov   ecx,512/32            ; count of dir entrys per sector = 16
419
 
420
  adr_analyze:
421
    mov   edi,[ebx+11]          ; file attribute
422
    and   edi,0xf
423
    cmp   edi,0xf
424
    je    adr_long_filename
425
    test  edi,0x8               ; skip over volume label
426
    jne   adr_long_filename     ; Note: label can be same name as file/dir
427
 
428
    mov   esi,[esp+0]           ; filename need to be uppercase
429
    mov   edi,ebx
430
    push  ecx
431
    mov   ecx,11
432
    cld
433
    rep   cmpsb                 ; compare 8+3 filename
434
    pop   ecx
435
    je    adr_found
436
 
437
  adr_long_filename:
438
    add   ebx,32                ; position of next dir entry
439
    dec   ecx
440
    jnz   adr_analyze
441
 
442
    mov   ecx,[longname_sec1]   ; save 2 previous directory sectors
443
    mov   [longname_sec1],eax   ; for delete long filename
444
    mov   [longname_sec2],ecx
445
    inc   eax                   ; next sector
446
    dec   edx
447
    jne   adr_new_sector
448
    cmp   [fat16_root],1        ; end of fat16 rootdir
449
    je    adr_not_found
450
 
451
  adr_next_cluster:
452
    mov   eax,[cluster_tmp]
453
    call  get_FAT               ; get next cluster
74 mario79 454
    cmp  [hd_error],0
455
    jne  adr_not_found
456
 
1 ha 457
    cmp   eax,2                 ; incorrect fat chain?
458
    jb    adr_not_found         ; yes
459
    cmp   eax,[fatRESERVED]     ; is it end of directory?
460
    jb    adr_new_cluster       ; no. analyse it
461
 
462
  adr_not_found:
463
    pop   edi edi esi edx ecx   ; first edi will remove ebx
464
    stc                         ; file not found
465
    ret
466
 
467
  adr_found:
468
    pop   edi edi esi edx ecx   ; first edi will remove ebx
469
    clc                         ; file found
470
    ret
471
 
472
 
473
analyze_directory_to_write:
474
;-----------------------------------------------------------
475
; input  : EAX = first cluster of the directory
476
; output : IF CARRY=0 EAX = sector where the empty pos is found
477
;                     EBX = pointer in buffer
478
;                     [buffer .. buffer+511]
479
;                     ECX,EDX,ESI,EDI not changed
480
;          IF CARRY=1 disk full or fat corrupted
481
; Note   : if cluster=0 it's changed to read rootdir
482
;-----------------------------------------------------------
483
    push  ecx edx edi
484
 
485
  adw_new_cluster:
486
    mov   [cluster_tmp],eax
487
    mov   [fat16_root],0
488
    cmp   eax,[LAST_CLUSTER]
489
    ja    adw_not_found         ; too big cluster number, something is wrong
490
    cmp   eax,2
491
    jnb   adw_data_cluster
492
 
493
    mov   eax,[ROOT_CLUSTER]    ; if cluster < 2 then read rootdir
256 diamond 494
    cmp   [fs_type],16
1 ha 495
    jne   adw_data_cluster
496
    mov   eax,[ROOT_START]
497
    mov   edx,[ROOT_SECTORS]
498
    mov   [fat16_root],1        ; flag for fat16 rootdir
499
    jmp   adw_new_sector
500
 
501
  adw_data_cluster:
502
    sub   eax,2
503
    mov   edx,[SECTORS_PER_CLUSTER]
504
    imul  eax,edx
505
    add   eax,[DATA_START]
506
 
507
  adw_new_sector:
508
    mov   ebx,buffer
509
    call  hd_read
74 mario79 510
    cmp  [hd_error],0
511
    jne  adw_not_found
512
 
1 ha 513
    mov   ecx,512/32            ; count of dir entrys per sector = 16
514
 
515
  adw_analyze:
516
    cmp   byte [ebx],0x00       ; is free entry?
517
    je    adw_found             ; yes
518
    cmp   byte [ebx],0xe5       ; is deleted entry?
519
    je    adw_found             ; yes
520
    add   ebx,32                ; position of next dir entry
521
    dec   ecx
522
    jnz   adw_analyze
523
 
524
    inc   eax                   ; next sector
525
    dec   edx
526
    jne   adw_new_sector
527
    cmp   [fat16_root],1        ; end of fat16 rootdir
528
    je    adw_not_found
529
 
530
    mov   eax,[cluster_tmp]
531
    call  get_FAT               ; get next cluster
74 mario79 532
    cmp   [hd_error],0
533
    jne   adw_not_found
534
 
1 ha 535
    cmp   eax,2                 ; incorrect fat chain?
536
    jb    adw_not_found         ; yes
537
    cmp   eax,[fatRESERVED]     ; is it end of directory?
538
    jb    adw_new_cluster       ; no. analyse it
539
 
540
    mov   eax,2                 ; this block of code add a new cluster
541
    call  get_free_FAT          ; for the directory because the directory
542
    jc    adw_not_found         ; is full
543
 
544
    mov   edx,[fatEND]          ; new end for directory
545
    call  set_FAT
74 mario79 546
    cmp  [hd_error],0
547
    jne  adw_not_found
1 ha 548
 
549
    push  eax                   ; save new cluster
550
    mov   edx,eax
551
    mov   eax,[cluster_tmp]     ; change last cluster to point new cluster
552
    call  set_FAT
74 mario79 553
    cmp  [hd_error],0
554
    jne  adw_not_found_1
555
 
1 ha 556
    mov   ecx,-1                ; remove 1 cluster from free disk space
557
    call  add_disk_free_space
74 mario79 558
    cmp  [hd_error],0
559
    jne    adw_not_found_1
1 ha 560
 
561
    mov   ecx,512/4
562
    xor   eax,eax
563
    mov   edi,buffer
564
    cld
565
    rep   stosd                 ; clear new directory cluster
566
    pop   eax
567
 
568
    sub   eax,2
569
    mov   ecx,[SECTORS_PER_CLUSTER]
570
    imul  eax,ecx
571
    add   eax,[DATA_START]
572
    mov   ebx,buffer
573
    push  eax                   ; save sector number
574
 
575
  adw_set_empty_directory:
576
    call  hd_write
74 mario79 577
    cmp   [hd_error],0
578
    jne   adw_not_found_1
579
 
1 ha 580
    inc   eax                   ; next sector
581
    dec   ecx
582
    jnz   adw_set_empty_directory
583
 
584
    pop   eax
585
 
586
  adw_found:
587
    pop   edi edx ecx
588
    clc                         ; free space found
589
    ret
74 mario79 590
  adw_not_found_1:
591
    add  esp,4
1 ha 592
  adw_not_found:
593
    pop   edi edx ecx
594
    stc                         ; free space not found
595
    ret
596
 
597
 
598
get_data_cluster:
599
;-----------------------------------------------------------
600
; input  : EAX = cluster
601
;          EBX = pointer to buffer
602
;          EDX = # blocks to read in buffer
603
;          ESI = # blocks to skip over
604
; output : if CARRY=0 ok EBX/EDX/ESI updated
605
;          if CARRY=1 cluster out of range
606
; Note   : if cluster=0 it's changed to read rootdir
607
;-----------------------------------------------------------
608
    push  eax ecx
609
 
610
    mov   [fat16_root],0
611
    cmp   eax,[LAST_CLUSTER]
612
    ja    gdc_error             ; too big cluster number, something is wrong
613
    cmp   eax,2
614
    jnb   gdc_cluster
615
 
616
    mov   eax,[ROOT_CLUSTER]    ; if cluster < 2 then read rootdir
256 diamond 617
    cmp   [fs_type],16
1 ha 618
    jne   gdc_cluster
619
    mov   eax,[ROOT_START]
620
    mov   ecx,[ROOT_SECTORS]    ; Note: not cluster size
621
    mov   [fat16_root],1        ; flag for fat16 rootdir
622
    jmp   gdc_read
623
 
624
  gdc_cluster:
625
    sub   eax,2
626
    mov   ecx,[SECTORS_PER_CLUSTER]
627
    imul  eax,ecx
628
    add   eax,[DATA_START]
629
 
630
  gdc_read:
631
    test  esi,esi               ; first wanted block
632
    je    gdcl1                 ; yes, skip count is 0
633
    dec   esi
634
    jmp   gdcl2
635
 
636
  gdcl1:
637
    call  hd_read
74 mario79 638
    cmp  [hd_error],0
379 serge 639
    jne  gdc_error
74 mario79 640
 
1 ha 641
    add   ebx,512               ; update pointer
642
    dec   edx
643
 
644
  gdcl2:
645
    test  edx,edx               ; is all read?
646
    je    out_of_read
647
 
648
    inc   eax                   ; next sector
649
    dec   ecx
650
    jnz   gdc_read
651
 
652
  out_of_read:
653
    pop   ecx eax
654
    clc
655
    ret
656
 
657
  gdc_error:
658
    pop   ecx eax
659
    stc
660
    ret
661
 
662
 
663
set_data_cluster:
664
;-----------------------------------------------------------
665
; input  : EAX = cluster
666
;          EBX = pointer to buffer
667
; output : if CARRY=0 ok
668
;          if CARRY=1 cluster out of range
669
;-----------------------------------------------------------
670
    push  eax ebx edx
671
 
672
    cmp   eax,[LAST_CLUSTER]
673
    ja    sdc_error             ; too big cluster number, something is wrong
674
    sub   eax,2
675
    jb    sdc_error             ; don't allow rootdir write
676
 
677
    mov   edx,[SECTORS_PER_CLUSTER]
678
    imul  eax,edx
679
    add   eax,[DATA_START]
680
 
681
  sdc_write:
682
    call  hd_write
74 mario79 683
    cmp   [hd_error],0
684
    jne   sdc_error
685
 
1 ha 686
    add   ebx,512               ; update pointer
687
    inc   eax
688
    dec   edx
689
    jnz   sdc_write
690
    pop   edx ebx eax
691
    clc
692
    ret
693
 
694
  sdc_error:
695
    pop   edx ebx eax
696
    stc
697
    ret
698
 
699
 
700
get_cluster_of_a_path:
701
;---------------------------------------------------------
702
; input  : EBX = pointer to a path string
703
;          (example: the path "/files/data/document" become
704
;                             "files......data.......document...0"
705
;          '.' = space char
706
;          '0' = char(0) (ASCII=0) !!! )
707
; output : if (CARRY=1) -> ERROR in the PATH
708
;          if (CARRY=0) -> EAX=cluster
709
;---------------------------------------------------------
710
    push  ebx edx
711
 
712
    mov   eax,[ROOT_CLUSTER]
713
    mov   edx,ebx
714
 
715
search_end_of_path:
716
    cmp   byte [edx],0
717
    je    found_end_of_path
718
 
719
    inc   edx ; '/'
720
    mov   ebx,edx
721
    call  analyze_directory
722
    jc    directory_not_found
723
 
724
    mov   eax,[ebx+20-2]        ; read the HIGH 16bit cluster field
725
    mov   ax,[ebx+26]           ; read the LOW 16bit cluster field
726
    and   eax,[fatMASK]
727
    add   edx,11                ; 8+3 (name+extension)
728
    jmp   search_end_of_path
729
 
730
found_end_of_path:
731
    pop   edx ebx
732
    clc                         ; no errors
733
    ret
734
 
735
directory_not_found:
736
    pop   edx ebx
737
    stc                         ; errors occour
738
    ret
739
 
740
 
741
bcd2bin:
742
;----------------------------------
743
; input  : AL=BCD number (eg. 0x11)
744
; output : AH=0
745
;          AL=decimal number (eg. 11)
746
;----------------------------------
747
    xor   ah,ah
748
    shl   ax,4
749
    shr   al,4
750
    aad
751
    ret
752
 
753
 
754
get_date_for_file:
755
;-----------------------------------------------------
756
; Get date from CMOS and pack day,month,year in AX
757
; DATE   bits  0..4   : day of month 0..31
758
;              5..8   : month of year 1..12
759
;              9..15  : count of years from 1980
760
;-----------------------------------------------------
761
    mov   al,0x7        ;day
762
    out   0x70,al
763
    in    al,0x71
764
    call  bcd2bin
765
    ror   eax,5
766
 
767
    mov   al,0x8        ;month
768
    out   0x70,al
769
    in    al,0x71
770
    call  bcd2bin
771
    ror   eax,4
772
 
773
    mov   al,0x9        ;year
774
    out   0x70,al
775
    in    al,0x71
776
    call  bcd2bin
777
    add   ax,20         ;because CMOS return only the two last
778
                        ;digit (eg. 2000 -> 00 , 2001 -> 01) and we
779
    rol   eax,9         ;need the difference with 1980 (eg. 2001-1980)
780
    ret
781
 
782
 
783
get_time_for_file:
784
;-----------------------------------------------------
785
; Get time from CMOS and pack hour,minute,second in AX
786
; TIME   bits  0..4   : second (the low bit is lost)
787
;              5..10  : minute 0..59
788
;              11..15 : hour 0..23
789
;-----------------------------------------------------
790
    mov   al,0x0        ;second
791
    out   0x70,al
792
    in    al,0x71
793
    call  bcd2bin
794
    ror   eax,6
795
 
796
    mov   al,0x2        ;minute
797
    out   0x70,al
798
    in    al,0x71
799
    call  bcd2bin
800
    ror   eax,6
801
 
802
    mov   al,0x4        ;hour
803
    out   0x70,al
804
    in    al,0x71
805
    call  bcd2bin
806
    rol   eax,11
807
    ret
808
 
809
 
810
set_current_time_for_entry:
811
;-----------------------------------------------------
812
; Set current time/date for file entry
813
; input  : ebx = file entry pointer
814
;-----------------------------------------------------
815
    push  eax
816
    call  get_time_for_file     ; update files date/time
817
    mov   [ebx+22],ax
818
    call  get_date_for_file
819
    mov   [ebx+24],ax
820
    pop   eax
821
    ret
822
 
823
 
824
 
825
add_disk_free_space:
826
;-----------------------------------------------------
827
; input  : ecx = cluster count
828
; Note   : negative = remove clusters from free space
829
;          positive = add clusters to free space
830
;-----------------------------------------------------
831
    test  ecx,ecx               ; no change
832
    je    add_dfs_no
256 diamond 833
    cmp   [fs_type],32         ; free disk space only used by fat32
1 ha 834
    jne   add_dfs_no
835
 
836
    push  eax ebx
837
    mov   eax,[ADR_FSINFO]
133 diamond 838
    mov   ebx,fsinfo_buffer
1 ha 839
    call  hd_read
74 mario79 840
    cmp  [hd_error],0
841
    jne  add_not_fs
842
 
1 ha 843
    cmp   dword [ebx+0x1fc],0xaa550000 ; check sector id
844
    jne   add_not_fs
845
 
846
    add   [ebx+0x1e8],ecx
847
    call  hd_write
133 diamond 848
;    cmp   [hd_error],0
849
;    jne   add_not_fs
1 ha 850
 
851
  add_not_fs:
852
    pop   ebx eax
853
 
854
  add_dfs_no:
855
    ret
856
 
857
 
858
file_write:
859
;--------------------------------------------------------------------------
860
;   INPUT : user-reg  register-in-this  meaning      symbol-in-this-routine
861
;
862
;            EAX        EDI            system call to write    /
863
;            EBX        EAX   (PAR0)   pointer to file-name    PAR0
864
;            EDX        ECX   (PAR1)   pointer to buffer       PAR1
865
;            ECX        EBX   (PAR2)   file size               PAR2
866
;            ESI        EDX   (PAR3)   pointer to path         PAR3
867
;
868
; output : eax = 0 - ok
869
;                3 - unknown FS
870
;                5 - file not found
871
;                8 - disk full
872
;               10 - access denied
873
;--------------------------------------------------------------------------
256 diamond 874
        cmp     [fs_type], 16
875
        jz      fat_ok_for_writing
876
        cmp     [fs_type], 32
877
        jz      fat_ok_for_writing
878
        push    ERROR_UNKNOWN_FS
879
        pop     eax
880
        ret
1 ha 881
 
882
  fat_ok_for_writing:
883
;    call  reserve_hd1
884
 
885
    pushad
886
 
887
    xor   edi,edi               ; don't allow directory remove
888
    call  file_delete           ; try to delete the file first
74 mario79 889
    cmp   [hd_error],0
890
    jne   exit_write_access_1
891
 
1 ha 892
    test  eax,eax
893
    jz    old_deleted           ; deleted ok
894
    cmp   eax,ERROR_FILE_NOT_FOUND
895
    jnz   exit_write_access     ; it exist but can't delete
896
 
897
  old_deleted:
898
    mov   ebx,PUSHAD_EDX
899
    call  get_cluster_of_a_path
900
    jnc   found_directory_for_writing
74 mario79 901
    cmp   [hd_error],0
902
    jne   exit_write_access
1 ha 903
 
904
  exit_writing_with_error:
905
    popad
906
    call  update_disk           ; write all of cache and fat to hd
74 mario79 907
    cmp   [hd_error],0
908
    jne   exit_write_access_2
909
 
1 ha 910
    mov   [hd1_status],0
911
    mov   eax,ERROR_FILE_NOT_FOUND
912
    ret
913
 
914
  exit_writing_disk_full_clear:
74 mario79 915
    cmp  [hd_error],0
916
    jne  exit_write_access_1
1 ha 917
    mov   eax,[sector_tmp]
918
    mov   ebx,buffer
919
    call  hd_read               ; read directory sector
74 mario79 920
    cmp  [hd_error],0
921
    jne  exit_write_access_1
922
 
1 ha 923
    mov   edx,[entry_pos]
924
    mov   byte [edx],0xe5       ; mark as deleted
925
    call  hd_write
74 mario79 926
    cmp   [hd_error],0
927
    jne   exit_write_access_1
928
 
1 ha 929
    mov   eax,[edx+20-2]        ; FAT entry
930
    mov   ax,[edx+26]
931
    and   eax,[fatMASK]
932
    call  clear_cluster_chain
933
 
934
  exit_writing_disk_full:
74 mario79 935
    cmp  [hd_error],0
936
    jne  exit_write_access_1
1 ha 937
    popad
938
    call  update_disk           ; write all of cache and fat to hd
74 mario79 939
    cmp   [hd_error],0
940
    jne   exit_write_access_2
1 ha 941
    mov   [hd1_status],0
942
    mov   eax,ERROR_DISK_FULL
943
    ret
944
 
945
  exit_write_access:
946
    popad
947
    call  update_disk           ; write all of cache and fat to hd
948
    mov   [hd1_status],0
949
    mov   eax,ERROR_ACCESS_DENIED
950
    ret
951
 
74 mario79 952
  exit_write_access_1:
953
    popad
954
  exit_write_access_2:
955
    mov   [hd1_status],0
956
    mov   eax,ERROR_ACCESS_DENIED
957
    ret
958
 
1 ha 959
found_directory_for_writing:
960
    call  analyze_directory_to_write
961
    jc    exit_writing_disk_full
962
 
963
    mov   [sector_tmp],eax
964
    mov   [entry_pos],ebx
965
    push  eax                   ; save directory sector
966
    mov   eax,2
967
    call  get_free_FAT
968
    mov   [cluster],eax         ; first free cluster
969
    pop   eax
970
    jc    exit_writing_disk_full
971
 
972
    mov   esi,PUSHAD_EAX        ; file name
973
    mov   edi,ebx               ; pointer in buffer
974
    mov   ecx,11
975
    cld
976
    rep   movsb
977
 
978
    mov   esi,PUSHAD_EBX        ; file size (bytes left)
979
    mov   [ebx+28],esi          ; file size
980
    mov   ecx,[cluster]
981
    mov   [ebx+26],cx           ; 16 bits low of cluster
982
    shr   ecx,16
983
    mov   [ebx+20],cx           ; 16 bits high of cluster (=0 fat16)
984
    mov   byte [ebx+11],0x20    ; attribute = archive
985
 
986
    call  set_current_time_for_entry
987
 
988
    mov   ebx,buffer            ; save the directory name,length,cluster
989
    call  hd_write
74 mario79 990
    cmp   [hd_error],0
991
    jne   exit_write_access_1
1 ha 992
 
993
    imul  edi,[SECTORS_PER_CLUSTER],512 ; edi = cluster size in bytes
994
    xor   ecx,ecx               ; cluster count
995
    mov   ebx,PUSHAD_ECX        ; ebx = buffer
996
 
997
hd_new_block_write:
998
 
999
    mov   eax,[cluster]         ; eax = block
1000
    call  set_data_cluster
74 mario79 1001
    cmp   [hd_error],0
1002
    jne   exit_write_access_1
1 ha 1003
 
1004
    sub   esi,edi               ; sub wrote bytes
1005
    jbe   file_saved_OK         ; end if all done
1006
    add   ebx,edi               ; update buffer position
1007
 
1008
    inc   eax
1009
    call  get_free_FAT          ; next free in FAT
1010
    jc    exit_writing_disk_full_clear
1011
 
1012
    mov   edx,eax
1013
    xchg  eax,[cluster]         ; get old cluster and save new cluster
1014
    call  set_FAT               ; add it in cluster chain
74 mario79 1015
    cmp  [hd_error],0
1016
    jne   exit_write_access_1
1017
 
1 ha 1018
    dec   ecx                   ; update cluster count
1019
    jmp   hd_new_block_write
1020
 
1021
file_saved_OK:
1022
 
1023
    mov   edx,[fatEND]          ; new end for cluster chain
1024
    call  set_FAT
74 mario79 1025
    cmp  [hd_error],0
1026
    jne   exit_write_access_1
1027
 
1 ha 1028
    dec   ecx                   ; update cluster count
1029
 
1030
    call  add_disk_free_space   ; remove clusters from free disk space
74 mario79 1031
    cmp  [hd_error],0
1032
    jne   exit_write_access_1
1 ha 1033
 
1034
    popad
1035
    call  update_disk           ; write all of cache and fat to hd
74 mario79 1036
    cmp   [hd_error],0
1037
    jne   exit_write_access_2
1 ha 1038
    mov   [hd1_status],0
1039
    xor   eax,eax
1040
    ret
1041
 
1042
 
1043
file_read:
1044
;--------------------------------------------------------------------------
1045
;   INPUT :  user-register register-in-this  meaning         symbol-in-this
1046
;
1047
;            EAX           EDI               system call to write   /
1048
;            EBX           EAX   (PAR0)      pointer to file-name   PAR0
1049
;            EDX           ECX   (PAR1)      pointer to buffer      PAR1
1050
;            ECX           EBX   (PAR2)   vt file blocks to read    PAR2
1051
;            ESI           EDX   (PAR3)      pointer to path        PAR3
1052
;            EDI           ESI            vt first 512 block to read
1053
;                          EDI               if 0 - read root
1054
;
1055
; output : eax = 0 - ok
1056
;                3 - unknown FS
1057
;                5 - file not found
1058
;                6 - end of file
1059
;                9 - fat table corrupted
74 mario79 1060
;               10 - access denied
1 ha 1061
;          ebx = size of file/directory
1062
;--------------------------------------------------------------------------
256 diamond 1063
        cmp     [fs_type], 16
1064
        jz      fat_ok_for_reading
1065
        cmp     [fs_type], 32
1066
        jz      fat_ok_for_reading
1 ha 1067
    xor   ebx,ebx
1068
    mov   eax,ERROR_UNKNOWN_FS
63 halyavin 1069
    mov   [hd1_status], ebx
1 ha 1070
    ret
1071
 
1072
  fat_ok_for_reading:
1073
;    call  reserve_hd1
1074
 
1075
    pushad
1076
 
1077
    mov   ebx,edx
1078
    call  get_cluster_of_a_path
1079
    jc    file_to_read_not_found
1080
 
1081
    test  edi,edi               ; read rootdir
1082
    jne   no_read_root
1083
 
1084
    xor   eax,eax
1085
    call  get_dir_size          ; return rootdir size
74 mario79 1086
    cmp   [hd_error],0
1087
    jne   file_access_denied
1088
 
1 ha 1089
    mov   [file_size],eax
1090
    mov   eax,[ROOT_CLUSTER]
1091
    jmp   file_read_start
1092
 
1093
  no_read_root:
1094
    mov   ebx,PUSHAD_EAX        ; file name
1095
    call  analyze_directory
1096
    jc    file_to_read_not_found
1097
 
1098
    mov   eax,[ebx+28]          ; file size
1099
    test  byte [ebx+11],0x10    ; is it directory?
1100
    jz    read_set_size         ; no
1101
 
1102
    mov   eax,[ebx+20-2]        ; FAT entry
1103
    mov   ax,[ebx+26]
1104
    and   eax,[fatMASK]
1105
    call  get_dir_size
74 mario79 1106
    cmp   [hd_error],0
1107
    jne   file_access_denied
1 ha 1108
 
1109
  read_set_size:
1110
    mov   [file_size],eax
1111
 
1112
    mov   eax,[ebx+20-2]        ; FAT entry
1113
    mov   ax,[ebx+26]
1114
    and   eax,[fatMASK]
1115
 
1116
  file_read_start:
1117
    mov   ebx,PUSHAD_ECX        ; pointer to buffer
1118
    mov   edx,PUSHAD_EBX        ; file blocks to read
1119
    mov   esi,PUSHAD_ESI        ; first 512 block to read
1120
 
1121
  file_read_new_cluster:
1122
    call  get_data_cluster
1123
    jc    file_read_eof         ; end of file or cluster out of range
1124
 
1125
    test  edx,edx               ; is all read?
1126
    je    file_read_OK          ; yes
1127
 
1128
    call  get_FAT               ; get next cluster
74 mario79 1129
    cmp   [hd_error],0
1130
    jne   file_access_denied
1131
 
1 ha 1132
    cmp   eax,[fatRESERVED]     ; end of file
1133
    jnb   file_read_eof
1134
    cmp   eax,2                 ; incorrect fat chain
1135
    jnb   file_read_new_cluster
1136
 
1137
    popad
1138
    mov   [hd1_status],0
1139
    mov   ebx,[file_size]
1140
    mov   eax,ERROR_FAT_TABLE
1141
    ret
1142
 
1143
  file_read_eof:
74 mario79 1144
    cmp   [hd_error],0
1145
    jne   file_access_denied
1 ha 1146
    popad
1147
    mov   [hd1_status],0
1148
    mov   ebx,[file_size]
1149
    mov   eax,ERROR_END_OF_FILE
1150
    ret
1151
 
1152
  file_read_OK:
1153
    popad
1154
    mov   [hd1_status],0
1155
    mov   ebx,[file_size]
1156
    xor   eax,eax
1157
    ret
1158
 
1159
  file_to_read_not_found:
74 mario79 1160
    cmp   [hd_error],0
1161
    jne   file_access_denied
1 ha 1162
    popad
1163
    mov   [hd1_status],0
1164
    xor   ebx,ebx
1165
    mov   eax,ERROR_FILE_NOT_FOUND
1166
    ret
1167
 
74 mario79 1168
  file_access_denied:
1169
    popad
1170
    mov   [hd1_status],0
1171
    xor   ebx,ebx
1172
    mov   eax,ERROR_ACCESS_DENIED
1173
    ret
1 ha 1174
 
1175
get_dir_size:
1176
;-----------------------------------------------------
1177
; input  : eax = first cluster (0=rootdir)
1178
; output : eax = directory size in bytes
1179
;-----------------------------------------------------
1180
    push  edx
1181
    xor   edx,edx               ; count of directory clusters
1182
    test  eax,eax
1183
    jnz   dir_size_next
1184
 
1185
    mov   eax,[ROOT_SECTORS]
1186
    shl   eax,9                 ; fat16 rootdir size in bytes
256 diamond 1187
    cmp   [fs_type],16
1 ha 1188
    je    dir_size_ret
1189
    mov   eax,[ROOT_CLUSTER]
1190
 
1191
  dir_size_next:
1192
    cmp   eax,2                 ; incorrect fat chain
1193
    jb    dir_size_end
1194
    cmp   eax,[fatRESERVED]     ; end of directory
1195
    ja    dir_size_end
1196
    call  get_FAT               ; get next cluster
74 mario79 1197
    cmp   [hd_error],0
1198
    jne   dir_size_ret
1199
 
1 ha 1200
    inc   edx
1201
    jmp   dir_size_next
1202
 
1203
  dir_size_end:
1204
    imul  eax,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes
1205
    imul  eax,edx
1206
 
1207
  dir_size_ret:
1208
    pop   edx
1209
    ret
1210
 
1211
 
1212
file_delete:
1213
;-----------------------------------------------------
1214
; input  : eax = file/directory name
1215
;          edx = path
1216
;          edi = 1 - allow directory remove else don't remove directory
1217
; output : eax = 0 - ok
1218
;                3 - unknown FS
1219
;                5 - file not found
1220
;               10 - access denied
1221
;-----------------------------------------------------
256 diamond 1222
        cmp     [fs_type], 16
1223
        jz      file_del_fat_ok
1224
        cmp     [fs_type], 32
1225
        jz      file_del_fat_ok
1226
        push    ERROR_UNKNOWN_FS
1227
        pop     eax
1228
        ret
1 ha 1229
 
1230
  file_del_fat_ok:
1231
    pushad
1232
 
1233
    mov   ebx,edx
1234
    call  get_cluster_of_a_path
1235
    jc    file_to_delete_not_found
1236
 
1237
    mov   ebx,PUSHAD_EAX        ; file/directory name
1238
    call  analyze_directory
1239
    jc    file_to_delete_not_found
1240
 
1241
    test  byte [ebx+11],0x10    ; is it directory?
335 diamond 1242
    jnz   delete_no_access
1 ha 1243
 
1244
  delete_notdir:
1245
    call  delete_entry_name
74 mario79 1246
    cmp   [hd_error],0
1247
    jne   delete_no_access
1248
 
1 ha 1249
    mov   eax,ecx               ; first cluster of file
1250
    call  clear_cluster_chain
74 mario79 1251
    cmp   [hd_error],0
1252
    jne   delete_no_access
1253
 
1 ha 1254
    popad
1255
    xor   eax,eax
1256
    ret
1257
 
74 mario79 1258
  delete_no_access_1:
1259
     add esp,4
1 ha 1260
  delete_no_access:
1261
    popad
1262
    mov   eax,ERROR_ACCESS_DENIED
1263
    ret
1264
 
1265
  file_to_delete_not_found:
74 mario79 1266
    cmp  [hd_error],0
1267
    jne  delete_no_access
1 ha 1268
    popad
1269
    mov   eax,ERROR_FILE_NOT_FOUND
1270
    ret
1271
 
1272
 
1273
clear_cluster_chain:
1274
;-----------------------------------------------------
1275
; input  : eax = first cluster
1276
;-----------------------------------------------------
1277
    push  eax ecx edx
1278
    xor   ecx,ecx               ; cluster count
1279
 
1280
  clean_new_chain:
1281
    cmp   eax,[LAST_CLUSTER]    ; end of file
1282
    ja    delete_OK
1283
    cmp   eax,2                 ; unfinished fat chain or zero length file
1284
    jb    delete_OK
1285
    cmp   eax,[ROOT_CLUSTER]    ; don't remove root cluster
1286
    jz    delete_OK
1287
 
1288
    xor   edx,edx
1289
    call  set_FAT               ; clear fat entry
74 mario79 1290
    cmp  [hd_error],0
1291
    jne  access_denied_01
1292
 
1 ha 1293
    inc   ecx                   ; update cluster count
1294
    mov   eax,edx               ; old cluster
1295
    jmp   clean_new_chain
1296
 
1297
  delete_OK:
1298
    call  add_disk_free_space   ; add clusters to free disk space
74 mario79 1299
  access_denied_01:
1 ha 1300
    pop   edx ecx eax
1301
    ret
1302
 
1303
 
1304
delete_entry_name:
1305
;-----------------------------------------------------
1306
; input  : eax = directory sector
1307
;          ebx = directory pointer in buffer
1308
;          longname_sec = 2 previous directory sectors
1309
; output : ecx = first cluster
1310
; change : eax,ebx,edx
1311
;-----------------------------------------------------
1312
    mov   byte [ebx],0xe5
1313
    mov   ecx,[ebx+20-2]        ; first cluster of file
1314
    mov   cx,[ebx+26]           ; 0 length files start cluster = 0
1315
    and   ecx,[fatMASK]
1316
 
1317
  delete_empty:
1318
    sub   ebx,32
1319
    cmp   ebx,buffer
1320
    jnb   delete_test_long
1321
 
1322
    mov   ebx,buffer
1323
    call  hd_write              ; write directory sector back
74 mario79 1324
    cmp   [hd_error],0
1325
    jne   delete_name_end
1326
 
1 ha 1327
    xor   eax,eax
1328
    xchg  eax,[longname_sec2]
1329
    xchg  eax,[longname_sec1]
1330
    test  eax,eax               ; is there previous directory sector?
1331
    jz    delete_name_end       ; no
1332
 
1333
    mov   ebx,buffer
1334
    call  hd_read               ; read previous sector
74 mario79 1335
    cmp  [hd_error],0
379 serge 1336
    jne  delete_name_end
74 mario79 1337
 
1 ha 1338
    mov   ebx,buffer+0x1e0      ; start from last entry
1339
 
1340
  delete_test_long:
1341
    mov   dh,[ebx+11]           ; file attribute
1342
    and   dh,0xf
1343
    cmp   dh,0xf
1344
    jne   delete_write_buffer
1345
 
1346
    cmp   byte [ebx],0x40       ; end of long dir entry?
1347
    mov   byte [ebx],0xe5
1348
    jb    delete_empty
1349
 
1350
  delete_write_buffer:
1351
    mov   ebx,buffer
1352
    call  hd_write              ; write directory sector back
1353
 
1354
  delete_name_end:
1355
    ret
1356
 
1357
 
1358
get_hd_info:
1359
;-----------------------------------------------------------
1360
; output : eax = 0 - ok
1361
;                3 - unknown FS
74 mario79 1362
;               10 - access denied
1 ha 1363
;          edx = cluster size in bytes
1364
;          ebx = total clusters on disk
1365
;          ecx = free clusters on disk
1366
;-----------------------------------------------------------
256 diamond 1367
        cmp     [fs_type], 16
1368
        jz      info_fat_ok
1369
        cmp     [fs_type], 32
1370
        jz      info_fat_ok
1 ha 1371
    xor   edx,edx
1372
    xor   ebx,ebx
1373
    xor   ecx,ecx
1374
    mov   eax,ERROR_UNKNOWN_FS
1375
    ret
1376
 
1377
  info_fat_ok:
1378
;    call  reserve_hd1
1379
 
1380
    xor   ecx,ecx               ; count of free clusters
1381
    mov   eax,2
1382
    mov   ebx,[LAST_CLUSTER]
1383
 
1384
  info_cluster:
1385
    push  eax
1386
    call  get_FAT               ; get cluster info
74 mario79 1387
    cmp   [hd_error],0
1388
    jne   info_access_denied
1389
 
1 ha 1390
    test  eax,eax               ; is it free?
1391
    jnz   info_used             ; no
1392
    inc   ecx
1393
 
1394
  info_used:
1395
    pop   eax
1396
    inc   eax
1397
    cmp   eax,ebx               ; is above last cluster?
1398
    jbe   info_cluster          ; no. test next cluster
1399
 
1400
    dec   ebx                   ; cluster count
1401
    imul  edx,[SECTORS_PER_CLUSTER],512 ; cluster size in bytes
1402
    mov   [hd1_status],0
1403
    xor   eax,eax
1404
    ret
1405
 
74 mario79 1406
  info_access_denied:
379 serge 1407
    add   esp,4
74 mario79 1408
    xor   edx,edx
1409
    xor   ebx,ebx
1410
    xor   ecx,ecx
1411
    mov   eax,ERROR_ACCESS_DENIED
1412
    ret
1 ha 1413
 
1414
update_disk:
1415
;-----------------------------------------------------------
1416
; write changed fat and cache to disk
1417
;-----------------------------------------------------------
1418
    cmp   [fat_change],0        ; is fat changed?
1419
    je    upd_no_change
1420
 
1421
    call  write_fat_sector
74 mario79 1422
    cmp   [hd_error],0
1423
    jne   update_disk_acces_denied
1 ha 1424
 
1425
  upd_no_change:
1426
 
1427
    call  write_cache
74 mario79 1428
  update_disk_acces_denied:
1 ha 1429
    ret
1430
 
1431
read_hd_file:
1432
;-----------------------------------------------------------------
1433
;
1434
; Converting old reading function for hd-application start.
1435
;
1436
; IN:
1437
;
1438
; eax - pointer to file (0 = read only first sector of drive: eg 'label')
1439
; ebx - file lenght
1440
; ecx - start 512 byte block number
1441
; edx - number of blocks to read
1442
; esi - pointer to return/work area (atleast 20 000 bytes)
1443
;
1444
; For new read function
1445
;
1446
; EAX   (PAR0)      pointer to file-name
1447
; ECX   (PAR1)      pointer to buffer
1448
; EBX   (PAR2)   vt file blocks to read
1449
; EDX   (PAR3)      pointer to path
1450
; ESI            vt first 512 block to read
1451
; EDI               if 0 - return root
1452
;--------------------------------------------------------------------------
1453
 
1454
    push  ecx esi edi
1455
    mov   esi,eax
1456
    mov   edi,startpath
1457
    mov   ecx,250
1458
    cld
1459
    rep   movsb
1460
    pop   edi esi ecx
1461
 
1462
    mov   eax,startpath
1463
    mov   [eax+ebx-12],byte 0
1464
 
1465
    push  eax ebx ecx edx esi
1466
 
1467
    pop   ecx ; pointer to buffer
1468
    add   ecx,1024
1469
    pop   ebx ; number of blocks to read
1470
    pop   esi ; first block to read
1471
    dec   esi
1472
    pop   eax ; file length
1473
    pop   edx ; pointer to path
1474
 
1475
    mov   edi,12
1476
    lea   eax,[eax+edx-12+1]
1477
    call  file_read
1478
 
1479
    ret
1480
 
71 diamond 1481
; \begin{diamond}
1482
hd_find_lfn:
1483
; in: esi->name
1484
; out: CF=1 - file not found
86 diamond 1485
;      else CF=0 and edi->direntry, eax=sector
83 diamond 1486
; destroys eax
1487
        push    esi edi
1488
        push    0
1489
        push    0
1490
        push    fat16_root_first
1491
        push    fat16_root_next
1492
        mov     eax, [ROOT_CLUSTER]
256 diamond 1493
        cmp     [fs_type], 32
83 diamond 1494
        jz      .fat32
1495
.loop:
1496
        call    fat_find_lfn
1497
        jc      .notfound
1498
        cmp     byte [esi], 0
1499
        jz      .found
1500
        test    byte [edi+11], 10h
1501
        jz      .notfound
1502
        and     dword [esp+12], 0
88 diamond 1503
        mov     eax, [edi+20-2]
1504
        mov     ax, [edi+26]    ; cluster
83 diamond 1505
.fat32:
1506
        mov     [esp+8], eax
1507
        mov     dword [esp+4], fat_notroot_first
1508
        mov     dword [esp], fat_notroot_next
1509
        jmp     .loop
71 diamond 1510
.notfound:
83 diamond 1511
        add     esp, 16
1512
        pop     edi esi
1513
        stc
1514
        ret
71 diamond 1515
.found:
86 diamond 1516
        lea     eax, [esp+8]
1517
        cmp     dword [eax], 0
1518
        jz      .root
1519
        call    fat_get_sector
1520
        jmp     .cmn
1521
.root:
1522
        mov     eax, [eax+4]
1523
        add     eax, [ROOT_START]
1524
.cmn:
83 diamond 1525
        add     esp, 20         ; CF=0
1526
        pop     esi
1527
        ret
74 mario79 1528
 
71 diamond 1529
;----------------------------------------------------------------
1530
;
1531
;  fs_HdRead - LFN variant for reading hard disk
1532
;
1533
;  esi  points to filename
1534
;  ebx  pointer to 64-bit number = first wanted byte, 0+
1535
;       may be ebx=0 - start from first byte
1536
;  ecx  number of bytes to read, 0+
1537
;  edx  mem location to return data
1538
;
77 diamond 1539
;  ret ebx = bytes read or 0xffffffff file not found
71 diamond 1540
;      eax = 0 ok read or other = errormsg
1541
;
1542
;--------------------------------------------------------------
1543
fs_HdRead:
256 diamond 1544
        cmp     [fs_type], 16
1545
        jz      @f
1546
        cmp     [fs_type], 32
1547
        jz      @f
1548
        cmp     [fs_type], 1
1549
        jz      ntfs_HdRead
1550
        or      ebx, -1
1551
        mov     eax, ERROR_UNKNOWN_FS
1552
        ret
71 diamond 1553
@@:
74 mario79 1554
    push    edi
1555
    cmp    byte [esi], 0
1556
    jnz    @f
71 diamond 1557
.noaccess:
74 mario79 1558
    pop    edi
1559
.noaccess_2:
1560
    or    ebx, -1
1561
    mov    eax, ERROR_ACCESS_DENIED
1562
    ret
379 serge 1563
 
74 mario79 1564
.noaccess_3:
1565
    add esp,4
1566
.noaccess_1:
1567
    add esp,4
1568
.noaccess_4:
1569
    add esp,4*5
1570
    jmp  .noaccess_2
1571
 
71 diamond 1572
@@:
74 mario79 1573
    call    hd_find_lfn
1574
    jnc    .found
1575
    pop    edi
1576
    cmp   [hd_error],0
1577
    jne   .noaccess_2
1578
    or    ebx, -1
1579
    mov    eax, ERROR_FILE_NOT_FOUND
1580
    ret
1581
 
71 diamond 1582
.found:
74 mario79 1583
    test    byte [edi+11], 0x10    ; do not allow read directories
1584
    jnz    .noaccess
1585
    test    ebx, ebx
1586
    jz    .l1
1587
    cmp    dword [ebx+4], 0
1588
    jz    @f
77 diamond 1589
        xor     ebx, ebx
71 diamond 1590
.reteof:
74 mario79 1591
    mov    eax, 6
1592
    pop    edi
1593
    ret
71 diamond 1594
@@:
74 mario79 1595
    mov    ebx, [ebx]
71 diamond 1596
.l1:
77 diamond 1597
        push    ecx edx
1598
        push    0
1599
        mov     eax, [edi+28]
1600
        sub     eax, ebx
1601
        jb      .eof
1602
        cmp     eax, ecx
1603
        jae     @f
1604
        mov     ecx, eax
1605
        mov     byte [esp], 6
1606
@@:
74 mario79 1607
    mov    eax, [edi+20-2]
1608
    mov    ax, [edi+26]
71 diamond 1609
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
1610
.new_cluster:
74 mario79 1611
    jecxz    .new_sector
1612
    test    eax, eax
1613
    jz    .eof
1614
    cmp    eax, [fatRESERVED]
1615
    jae    .eof
1616
    mov    [cluster_tmp], eax
1617
    dec    eax
1618
    dec    eax
1619
    mov    edi, [SECTORS_PER_CLUSTER]
1620
    imul    eax, edi
1621
    add    eax, [DATA_START]
71 diamond 1622
.new_sector:
74 mario79 1623
    test    ecx, ecx
1624
    jz    .done
1625
    sub    ebx, 512
1626
    jae    .skip
1627
    add    ebx, 512
1628
    jnz    .force_buf
1629
    cmp    ecx, 512
1630
    jb    .force_buf
71 diamond 1631
; we may read directly to given buffer
74 mario79 1632
    push    ebx
1633
    mov    ebx, edx
1634
    call    hd_read
1635
    cmp  [hd_error],0
379 serge 1636
    jne  .noaccess_1
74 mario79 1637
    pop    ebx
1638
    add    edx, 512
1639
    sub    ecx, 512
1640
    jmp    .skip
71 diamond 1641
.force_buf:
1642
; we must read sector to temporary buffer and then copy it to destination
74 mario79 1643
    push    eax ebx
1644
    mov    ebx, buffer
1645
    call    hd_read
1646
    cmp  [hd_error],0
1647
    jne  .noaccess_3
1648
 
1649
    mov    eax, ebx
1650
    pop    ebx
1651
    add    eax, ebx
1652
    push    ecx
1653
    add    ecx, ebx
1654
    cmp    ecx, 512
1655
    jbe    @f
1656
    mov    ecx, 512
71 diamond 1657
@@:
74 mario79 1658
    sub    ecx, ebx
1659
    mov    ebx, edx
1660
    call    memmove
1661
    add    edx, ecx
1662
    sub    [esp], ecx
1663
    pop    ecx
1664
    pop    eax
1665
    xor    ebx, ebx
71 diamond 1666
.skip:
74 mario79 1667
    inc    eax
1668
    dec    edi
1669
    jnz    .new_sector
1670
    mov    eax, [cluster_tmp]
1671
    call    get_FAT
1672
    cmp   [hd_error],0
1673
    jne   .noaccess_4
1674
 
1675
    jmp    .new_cluster
71 diamond 1676
.done:
77 diamond 1677
        mov     ebx, edx
1678
        pop     eax edx ecx edi
1679
        sub     ebx, edx
1680
        ret
71 diamond 1681
.eof:
77 diamond 1682
        mov     ebx, edx
1683
        pop     eax edx ecx
1684
        sub     ebx, edx
1685
        jmp     .reteof
75 diamond 1686
 
1687
;----------------------------------------------------------------
1688
;
1689
;  fs_HdReadFolder - LFN variant for reading hard disk folder
1690
;
1691
;  esi  points to filename
78 diamond 1692
;  ebx  pointer to structure 32-bit number = first wanted block, 0+
1693
;                          & flags (bitfields)
1694
; flags: bit 0: 0=ANSI names, 1=UNICODE names
75 diamond 1695
;  ecx  number of blocks to read, 0+
1696
;  edx  mem location to return data
1697
;
77 diamond 1698
;  ret ebx = blocks read or 0xffffffff folder not found
75 diamond 1699
;      eax = 0 ok read or other = errormsg
1700
;
1701
;--------------------------------------------------------------
1702
fs_HdReadFolder:
256 diamond 1703
        cmp     [fs_type], 1
1704
        jz      ntfs_HdReadFolder
1705
        cmp     [fs_type], 16
1706
        jz      @f
1707
        cmp     [fs_type], 32
1708
        jz      @f
1709
        push    ERROR_UNSUPPORTED_FS
1710
        pop     eax
1711
        or      ebx, -1
1712
        ret
1713
@@:
75 diamond 1714
        mov     eax, [ROOT_CLUSTER]
1715
        push    edi
1716
        cmp     byte [esi], 0
1717
        jz      .doit
1718
        call    hd_find_lfn
1719
        jnc     .found
1720
        pop     edi
1721
        or      ebx, -1
1722
        mov     eax, ERROR_FILE_NOT_FOUND
1723
        ret
1724
.found:
1725
        test    byte [edi+11], 0x10     ; do not allow read files
1726
        jnz     .found_dir
1727
        pop     edi
1728
        or      ebx, -1
1729
        mov     eax, ERROR_ACCESS_DENIED
1730
        ret
1731
.found_dir:
1732
        mov     eax, [edi+20-2]
1733
        mov     ax, [edi+26]    ; eax=cluster
1734
.doit:
1735
        push    esi ecx
1736
        push    ebp
1737
        sub     esp, 262*2      ; reserve space for LFN
1738
        mov     ebp, esp
78 diamond 1739
        push    dword [ebx+4]   ; for fat_get_name: read ANSI/UNICODE name
1740
        mov     ebx, [ebx]
75 diamond 1741
; init header
1742
        push    eax ecx
1743
        mov     edi, edx
1744
        mov     ecx, 32/4
1745
        xor     eax, eax
1746
        rep     stosd
1747
        pop     ecx eax
1748
        mov     byte [edx], 1   ; version
1749
        mov     esi, edi        ; esi points to BDFE
1750
.new_cluster:
1751
        mov     [cluster_tmp], eax
1752
        test    eax, eax
1753
        jnz     @f
256 diamond 1754
        cmp     [fs_type], 32
75 diamond 1755
        jz      .notfound
1756
        mov     eax, [ROOT_START]
1757
        push    [ROOT_SECTORS]
1758
        push    ebx
1759
        jmp     .new_sector
1760
@@:
1761
        dec     eax
1762
        dec     eax
1763
        imul    eax, [SECTORS_PER_CLUSTER]
1764
        push    [SECTORS_PER_CLUSTER]
1765
        add     eax, [DATA_START]
1766
        push    ebx
1767
.new_sector:
1768
        mov     ebx, buffer
1769
        mov     edi, ebx
1770
        call    hd_read
1771
        cmp     [hd_error], 0
1772
        jnz     .notfound2
1773
        add     ebx, 512
1774
        push    eax
1775
.l1:
1776
        call    fat_get_name
1777
        jc      .l2
1778
        cmp     byte [edi+11], 0xF
1779
        jnz     .do_bdfe
1780
        add     edi, 0x20
1781
        cmp     edi, ebx
1782
        jb      .do_bdfe
1783
        pop     eax
1784
        inc     eax
1785
        dec     dword [esp+4]
1786
        jnz     @f
1787
        mov     eax, [cluster_tmp]
1788
        test    eax, eax
1789
        jz      .done
1790
        call    get_FAT
1791
        cmp     [hd_error], 0
1792
        jnz     .notfound2
1793
        cmp     eax, 2
1794
        jb      .done
1795
        cmp     eax, [fatRESERVED]
1796
        jae     .done
1797
        push    eax
1798
        mov     eax, [SECTORS_PER_CLUSTER]
1799
        mov     [esp+8], eax
1800
        pop     eax
1801
        mov     [cluster_tmp], eax
1802
        dec     eax
1803
        dec     eax
1804
        imul    eax, [SECTORS_PER_CLUSTER]
1805
        add     eax, [DATA_START]
1806
@@:
1807
        mov     ebx, buffer
1808
        mov     edi, ebx
1809
        call    hd_read
1810
        cmp     [hd_error], 0
1811
        jnz     .notfound2
1812
        add     ebx, 512
1813
        push    eax
1814
.do_bdfe:
1815
        inc     dword [edx+8]   ; new file found
1816
        dec     dword [esp+4]
1817
        jns     .l2
1818
        dec     ecx
1819
        js      .l2
1820
        inc     dword [edx+4]   ; new file block copied
1821
        call    fat_entry_to_bdfe
1822
.l2:
1823
        add     edi, 0x20
1824
        cmp     edi, ebx
1825
        jb      .l1
1826
        pop     eax
1827
        inc     eax
1828
        dec     dword [esp+4]
1829
        jnz     .new_sector
1830
        mov     eax, [cluster_tmp]
1831
        test    eax, eax
1832
        jz      .done
1833
        call    get_FAT
1834
        cmp     [hd_error], 0
1835
        jnz     .notfound2
1836
        cmp     eax, 2
1837
        jb      .done
1838
        cmp     eax, [fatRESERVED]
1839
        jae     .done
1840
        push    eax
1841
        mov     eax, [SECTORS_PER_CLUSTER]
1842
        mov     [esp+8], eax
1843
        pop     eax
1844
        pop     ebx
1845
        add     esp, 4
1846
        jmp     .new_cluster
1847
.notfound2:
1848
        add     esp, 8
1849
.notfound:
1850
        add     esp, 262*2+4
1851
        pop     ebp ecx esi edi
1852
        mov     eax, ERROR_FILE_NOT_FOUND
1853
        or      ebx, -1
1854
        ret
1855
.done:
1856
        add     esp, 262*2+4+8
1857
        pop     ebp
77 diamond 1858
        mov     ebx, [edx+4]
75 diamond 1859
        xor     eax, eax
1860
        dec     ecx
1861
        js      @f
1862
        mov     al, ERROR_END_OF_FILE
1863
@@:
1864
        pop     ecx esi edi
1865
        ret
1866
 
83 diamond 1867
fat16_root_next:
1868
        cmp     edi, buffer+0x200-0x20
1869
        jae     fat16_root_next_sector
1870
        add     edi, 0x20
1871
        ret     ; CF=0
1872
fat16_root_next_sector:
1873
; read next sector
171 diamond 1874
        push    [longname_sec2]
1875
        pop     [longname_sec1]
83 diamond 1876
        push    ecx
1877
        mov     ecx, [eax+4]
171 diamond 1878
        push    ecx
1879
        add     ecx, [ROOT_START]
1880
        mov     [longname_sec2], ecx
1881
        pop     ecx
83 diamond 1882
        inc     ecx
1883
        mov     [eax+4], ecx
1884
        cmp     ecx, [ROOT_SECTORS]
1885
        pop     ecx
1886
        jae     fat16_root_first.readerr
1887
fat16_root_first:
1888
        mov     eax, [eax+4]
1889
        add     eax, [ROOT_START]
1890
        push    ebx
1891
        mov     edi, buffer
1892
        mov     ebx, edi
1893
        call    hd_read
1894
        pop     ebx
1895
        cmp     [hd_error], 0
1896
        jnz     .readerr
1897
        ret     ; CF=0
1898
.readerr:
1899
        stc
1900
        ret
1901
fat16_root_begin_write:
1902
        push    edi eax
1903
        call    fat16_root_first
1904
        pop     eax edi
1905
        ret
1906
fat16_root_end_write:
1907
        pusha
1908
        mov     eax, [eax+4]
1909
        add     eax, [ROOT_START]
1910
        mov     ebx, buffer
1911
        call    hd_write
1912
        popa
1913
        ret
1914
fat16_root_next_write:
1915
        cmp     edi, buffer+0x200
1916
        jae     @f
1917
        ret
1918
@@:
1919
        call    fat16_root_end_write
1920
        jmp     fat16_root_next_sector
1921
fat16_root_extend_dir:
1922
        stc
1923
        ret
1924
 
1925
fat_notroot_next:
1926
        cmp     edi, buffer+0x200-0x20
1927
        jae     fat_notroot_next_sector
1928
        add     edi, 0x20
1929
        ret     ; CF=0
1930
fat_notroot_next_sector:
171 diamond 1931
        push    [longname_sec2]
1932
        pop     [longname_sec1]
1933
        push    eax
1934
        call    fat_get_sector
1935
        mov     [longname_sec2], eax
1936
        pop     eax
83 diamond 1937
        push    ecx
1938
        mov     ecx, [eax+4]
1939
        inc     ecx
1940
        cmp     ecx, [SECTORS_PER_CLUSTER]
1941
        jae     fat_notroot_next_cluster
1942
        mov     [eax+4], ecx
1943
        jmp     @f
1944
fat_notroot_next_cluster:
1945
        push    eax
1946
        mov     eax, [eax]
1947
        call    get_FAT
1948
        mov     ecx, eax
1949
        pop     eax
1950
        cmp     [hd_error], 0
1951
        jnz     fat_notroot_next_err
1952
        cmp     ecx, [fatRESERVED]
1953
        jae     fat_notroot_next_err
1954
        mov     [eax], ecx
1955
        and     dword [eax+4], 0
1956
@@:
1957
        pop     ecx
1958
fat_notroot_first:
1959
        call    fat_get_sector
1960
        push    ebx
1961
        mov     edi, buffer
1962
        mov     ebx, edi
1963
        call    hd_read
1964
        pop     ebx
1965
        cmp     [hd_error], 0
1966
        jnz     @f
1967
        ret     ; CF=0
1968
fat_notroot_next_err:
1969
        pop     ecx
1970
@@:
1971
        stc
1972
        ret
1973
fat_notroot_begin_write:
1974
        push    eax edi
1975
        call    fat_notroot_first
1976
        pop     edi eax
1977
        ret
1978
fat_notroot_end_write:
1979
        call    fat_get_sector
1980
        push    ebx
1981
        mov     ebx, buffer
1982
        call    hd_write
1983
        pop     ebx
1984
        ret
1985
fat_notroot_next_write:
1986
        cmp     edi, buffer+0x200
1987
        jae     @f
1988
        ret
1989
@@:
1990
        push    eax
1991
        call    fat_notroot_end_write
1992
        pop     eax
1993
        jmp     fat_notroot_next_sector
1994
fat_notroot_extend_dir:
1995
        push    eax
1996
        mov     eax, [eax]
1997
        call    get_free_FAT
1998
        jnc     .found
1999
        pop     eax
2000
        ret     ; CF=1
2001
.found:
2002
        push    edx
2003
        mov     edx, [fatEND]
2004
        call    set_FAT
2005
        mov     edx, eax
2006
        mov     eax, [esp+4]
2007
        mov     eax, [eax]
2008
        push    edx
2009
        call    set_FAT
2010
        pop     edx
2011
        cmp     [hd_error], 0
2012
        jz      @f
2013
        pop     edx
2014
        pop     eax
2015
        stc
2016
        ret
2017
@@:
2018
        push    ecx
2019
        or      ecx, -1
2020
        call    add_disk_free_space
2021
; zero new cluster
2022
        mov     ecx, 512/4
2023
        mov     edi, buffer
2024
        push    edi
2025
        xor     eax, eax
2026
        rep     stosd
2027
        pop     edi
2028
        pop     ecx
2029
        mov     eax, [esp+4]
2030
        mov     [eax], edx
2031
        and     dword [eax+4], 0
2032
        pop     edx
2033
        mov     eax, [eax]
2034
        dec     eax
2035
        dec     eax
2036
        push    ebx ecx
2037
        mov     ecx, [SECTORS_PER_CLUSTER]
2038
        imul    eax, ecx
2039
        add     eax, [DATA_START]
2040
        mov     ebx, edi
2041
@@:
2042
        call    hd_write
2043
        inc     eax
2044
        loop    @b
2045
        pop     ecx ebx eax
2046
        clc
2047
        ret
2048
 
2049
fat_get_sector:
2050
        push    ecx
2051
        mov     ecx, [eax]
2052
        dec     ecx
2053
        dec     ecx
2054
        imul    ecx, [SECTORS_PER_CLUSTER]
2055
        add     ecx, [DATA_START]
2056
        add     ecx, [eax+4]
2057
        mov     eax, ecx
2058
        pop     ecx
2059
        ret
2060
 
2061
;----------------------------------------------------------------
2062
;
2063
;  fs_HdRewrite - LFN variant for writing hard disk
2064
;
2065
;  esi  points to filename
2066
;  ebx  ignored (reserved)
2067
;  ecx  number of bytes to write, 0+
2068
;  edx  mem location to data
2069
;
2070
;  ret ebx = number of written bytes
2071
;      eax = 0 ok read or other = errormsg
2072
;
2073
;--------------------------------------------------------------
2074
fshrad:
2075
        mov     eax, ERROR_ACCESS_DENIED
2076
        xor     ebx, ebx
2077
        ret
2078
fshrfs:
2079
        mov     eax, ERROR_UNKNOWN_FS
2080
        xor     ebx, ebx
2081
        ret
2082
 
321 diamond 2083
fs_HdCreateFolder:
2084
        mov     al, 1
2085
        jmp     fs_HdRewrite.common
2086
 
83 diamond 2087
fs_HdRewrite:
321 diamond 2088
        xor     eax, eax
2089
.common:
256 diamond 2090
        cmp     [fs_type], 1
2091
        jz      ntfs_HdRewrite
2092
        cmp     [fs_type], 16
2093
        jz      @f
2094
        cmp     [fs_type], 32
2095
        jnz     fshrfs
2096
@@:
83 diamond 2097
        cmp     byte [esi], 0
2098
        jz      fshrad
2099
        pushad
2100
        xor     ebp, ebp
2101
        push    esi
2102
@@:
2103
        lodsb
2104
        test    al, al
2105
        jz      @f
2106
        cmp     al, '/'
2107
        jnz     @b
2108
        lea     ebp, [esi-1]
2109
        jmp     @b
2110
@@:
2111
        pop     esi
2112
        test    ebp, ebp
2113
        jnz     .noroot
2114
        mov     ebp, [ROOT_CLUSTER]
256 diamond 2115
        cmp     [fs_type], 32
83 diamond 2116
        jz      .pushnotroot
2117
        push    fat16_root_extend_dir
2118
        push    fat16_root_end_write
2119
        push    fat16_root_next_write
2120
        push    fat16_root_begin_write
2121
        xor     ebp, ebp
2122
        push    ebp
2123
        push    ebp
2124
        push    fat16_root_first
2125
        push    fat16_root_next
2126
        jmp     .common1
2127
.noroot:
335 diamond 2128
        mov     eax, ERROR_ACCESS_DENIED
2129
        cmp     byte [ebp+1], 0
2130
        jz      .ret1
83 diamond 2131
; check existence
2132
        mov     byte [ebp], 0
2133
        call    hd_find_lfn
2134
        mov     byte [ebp], '/'
2135
        lea     esi, [ebp+1]
2136
        jnc     @f
2137
        mov     eax, ERROR_FILE_NOT_FOUND
2138
.ret1:
2139
        mov     [esp+28], eax
2140
        popad
2141
        xor     ebx, ebx
2142
        ret
2143
@@:
2144
        test    byte [edi+11], 0x10     ; must be directory
2145
        mov     eax, ERROR_ACCESS_DENIED
2146
        jz      .ret1
2147
        mov     ebp, [edi+20-2]
2148
        mov     bp, [edi+26]            ; ebp=cluster
2149
        mov     eax, ERROR_FAT_TABLE
2150
        cmp     ebp, 2
2151
        jb      .ret1
2152
.pushnotroot:
2153
        push    fat_notroot_extend_dir
2154
        push    fat_notroot_end_write
2155
        push    fat_notroot_next_write
2156
        push    fat_notroot_begin_write
2157
        push    0
2158
        push    ebp
2159
        push    fat_notroot_first
2160
        push    fat_notroot_next
2161
.common1:
2162
        call    fat_find_lfn
2163
        jc      .notfound
321 diamond 2164
; found
91 diamond 2165
        test    byte [edi+11], 10h
321 diamond 2166
        jz      .exists_file
2167
; found directory; if we are creating directory, return OK,
2168
;                  if we are creating file, say "access denied"
2169
        add     esp, 32
2170
        popad
2171
        test    al, al
2172
        mov     eax, ERROR_ACCESS_DENIED
91 diamond 2173
        jz      @f
321 diamond 2174
        mov     al, 0
2175
@@:
2176
        xor     ebx, ebx
2177
        ret
2178
.exists_file:
2179
; found file; if we are creating directory, return "access denied",
2180
;             if we are creating file, delete existing file and continue
2181
        cmp     byte [esp+32+28], 0
2182
        jz      @f
91 diamond 2183
        add     esp, 32
2184
        popad
2185
        mov     eax, ERROR_ACCESS_DENIED
2186
        xor     ebx, ebx
2187
        ret
2188
@@:
2189
; delete FAT chain
83 diamond 2190
        push    edi
2191
        xor     eax, eax
2192
        mov     dword [edi+28], eax     ; zero size
2193
        xor     ecx, ecx
2194
        mov     eax, [edi+20-2]
2195
        mov     ax, [edi+26]
2196
        mov     word [edi+20], cx
2197
        mov     word [edi+26], cx
2198
        test    eax, eax
2199
        jz      .done1
2200
@@:
2201
        cmp     eax, [fatRESERVED]
2202
        jae     .done1
2203
        push    edx
2204
        xor     edx, edx
2205
        call    set_FAT
2206
        mov     eax, edx
2207
        pop     edx
2208
        inc     ecx
2209
        jmp     @b
2210
.done1:
2211
        pop     edi
2212
        call    get_time_for_file
2213
        mov     [edi+22], ax
2214
        call    get_date_for_file
2215
        mov     [edi+24], ax
2216
        mov     [edi+18], ax
2217
        or      byte [edi+11], 20h      ; set 'archive' attribute
2218
        jmp     .doit
2219
.notfound:
2220
; file is not found; generate short name
2221
        call    fat_name_is_legal
2222
        jc      @f
2223
        add     esp, 32
2224
        popad
2225
        mov     eax, ERROR_FILE_NOT_FOUND
2226
        xor     ebx, ebx
2227
        ret
2228
@@:
2229
        sub     esp, 12
2230
        mov     edi, esp
2231
        call    fat_gen_short_name
2232
.test_short_name_loop:
2233
        push    esi edi ecx
2234
        mov     esi, edi
2235
        lea     eax, [esp+12+12+8]
2236
        mov     [eax], ebp
2237
        and     dword [eax+4], 0
2238
        call    dword [eax-4]
2239
        jc      .found
2240
.test_short_name_entry:
2241
        cmp     byte [edi+11], 0xF
2242
        jz      .test_short_name_cont
2243
        mov     ecx, 11
2244
        push    esi edi
2245
        repz    cmpsb
2246
        pop     edi esi
2247
        jz      .short_name_found
2248
.test_short_name_cont:
2249
        lea     eax, [esp+12+12+8]
2250
        call    dword [eax-8]
2251
        jnc     .test_short_name_entry
2252
        jmp     .found
2253
.short_name_found:
2254
        pop     ecx edi esi
2255
        call    fat_next_short_name
2256
        jnc     .test_short_name_loop
2257
.disk_full:
2258
        add     esp, 12+32
2259
        popa
2260
        mov     eax, ERROR_DISK_FULL
2261
        xor     ebx, ebx
2262
        ret
2263
.found:
2264
        pop     ecx edi esi
2265
; now find space in directory
2266
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
2267
        mov     al, '~'
2268
        push    ecx edi
2269
        mov     ecx, 8
2270
        repnz   scasb
2271
        push    1
2272
        pop     eax     ; 1 entry
2273
        jnz     .notilde
2274
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
2275
        xor     eax, eax
2276
@@:
2277
        cmp     byte [esi], 0
2278
        jz      @f
2279
        inc     esi
2280
        inc     eax
2281
        jmp     @b
2282
@@:
2283
        sub     esi, eax
2284
        add     eax, 12+13
2285
        mov     ecx, 13
2286
        push    edx
2287
        cdq
2288
        div     ecx
2289
        pop     edx
2290
.notilde:
2291
        push    -1
2292
        push    -1
2293
        push    -1
2294
; find  successive entries in directory
2295
        xor     ecx, ecx
2296
        push    eax
2297
        lea     eax, [esp+16+8+12+8]
2298
        mov     [eax], ebp
2299
        and     dword [eax+4], 0
2300
        call    dword [eax-4]
2301
        pop     eax
2302
        jnc     .scan_dir
2303
.fsfrfe3:
2304
        add     esp, 12+8+12+32
2305
        popad
2306
        mov     eax, 11
2307
        xor     ebx, ebx
2308
        ret
2309
.scan_dir:
2310
        cmp     byte [edi], 0
2311
        jz      .free
2312
        cmp     byte [edi], 0xE5
2313
        jz      .free
2314
        xor     ecx, ecx
2315
.scan_cont:
2316
        push    eax
2317
        lea     eax, [esp+16+8+12+8]
2318
        call    dword [eax-8]
2319
        pop     eax
2320
        jnc     .scan_dir
2321
        cmp     [hd_error], 0
2322
        jnz     .fsfrfe3
2323
        push    eax
2324
        lea     eax, [esp+16+8+12+8]
2325
        call    dword [eax+20]          ; extend directory
2326
        pop     eax
2327
        jnc     .scan_dir
2328
        add     esp, 12+8+12+32
2329
        popad
2330
        mov     eax, ERROR_DISK_FULL
2331
        xor     ebx, ebx
2332
        ret
2333
.free:
2334
        test    ecx, ecx
2335
        jnz     @f
2336
        mov     [esp], edi
2337
        mov     ecx, [esp+12+8+12+8]
2338
        mov     [esp+4], ecx
2339
        mov     ecx, [esp+12+8+12+12]
2340
        mov     [esp+8], ecx
2341
        xor     ecx, ecx
2342
@@:
2343
        inc     ecx
2344
        cmp     ecx, eax
2345
        jb      .scan_cont
2346
; found!
2347
; calculate name checksum
2348
        push    esi ecx
2349
        mov     esi, [esp+8+12]
2350
        mov     ecx, 11
2351
        xor     eax, eax
2352
@@:
2353
        ror     al, 1
2354
        add     al, [esi]
2355
        inc     esi
2356
        loop    @b
2357
        pop     ecx esi
2358
        pop     edi
2359
        pop     dword [esp+8+12+12]
2360
        pop     dword [esp+8+12+12]
2361
; edi points to first entry in free chunk
2362
        dec     ecx
2363
        jz      .nolfn
2364
        push    esi
2365
        push    eax
2366
        lea     eax, [esp+8+8+12+8]
2367
        call    dword [eax+8]         ; begin write
2368
        mov     al, 40h
2369
.writelfn:
2370
        or      al, cl
2371
        mov     esi, [esp+4]
2372
        push    ecx
2373
        dec     ecx
2374
        imul    ecx, 13
2375
        add     esi, ecx
2376
        stosb
2377
        mov     cl, 5
2378
        call    fs_RamdiskRewrite.read_symbols
2379
        mov     ax, 0xF
2380
        stosw
2381
        mov     al, [esp+4]
2382
        stosb
2383
        mov     cl, 6
2384
        call    fs_RamdiskRewrite.read_symbols
2385
        xor     eax, eax
2386
        stosw
2387
        mov     cl, 2
2388
        call    fs_RamdiskRewrite.read_symbols
2389
        pop     ecx
2390
        lea     eax, [esp+8+8+12+8]
2391
        call    dword [eax+12]         ; next write
2392
        xor     eax, eax
2393
        loop    .writelfn
2394
        pop     eax
2395
        pop     esi
2396
;        lea     eax, [esp+8+12+8]
2397
;        call    dword [eax+16]          ; end write
2398
.nolfn:
2399
        xchg    esi, [esp]
2400
        mov     ecx, 11
2401
        rep     movsb
2402
        mov     word [edi], 20h         ; attributes
2403
        sub     edi, 11
2404
        pop     esi ecx
2405
        add     esp, 12
2406
        mov     byte [edi+13], 0        ; tenths of a second at file creation time
2407
        call    get_time_for_file
2408
        mov     [edi+14], ax            ; creation time
2409
        mov     [edi+22], ax            ; last write time
2410
        call    get_date_for_file
2411
        mov     [edi+16], ax            ; creation date
2412
        mov     [edi+24], ax            ; last write date
2413
        mov     [edi+18], ax            ; last access date
2414
        xor     ecx, ecx
2415
        mov     word [edi+20], cx       ; high word of cluster
2416
        mov     word [edi+26], cx       ; low word of cluster - to be filled
2417
        mov     dword [edi+28], ecx     ; file size - to be filled
321 diamond 2418
        cmp     byte [esp+32+28], cl
2419
        jz      .doit
2420
; create directory
2421
        mov     byte [edi+11], 10h      ; attributes: folder
2422
        mov     edx, edi
2423
        lea     eax, [esp+8]
2424
        call    dword [eax+16]  ; flush directory
2425
        push    ecx
2426
        mov     ecx, [SECTORS_PER_CLUSTER]
2427
        shl     ecx, 9
2428
        jmp     .doit2
83 diamond 2429
.doit:
2430
        lea     eax, [esp+8]
2431
        call    dword [eax+16]  ; flush directory
2432
        push    ecx
2433
        mov     ecx, [esp+4+32+24]
321 diamond 2434
.doit2:
83 diamond 2435
        push    ecx
2436
        push    edi
2437
        mov     esi, edx
2438
        test    ecx, ecx
2439
        jz      .done
2440
        mov     eax, 2
2441
        call    get_free_FAT
2442
        jc      .diskfull
2443
        push    eax
2444
        mov     [edi+26], ax
2445
        shr     eax, 16
2446
        mov     [edi+20], ax
2447
        lea     eax, [esp+16+8]
2448
        call    dword [eax+16]  ; flush directory
2449
        pop     eax
2450
        push    edx
2451
        mov     edx, [fatEND]
2452
        call    set_FAT
2453
        pop     edx
2454
.write_cluster:
2455
        push    eax
2456
        dec     eax
2457
        dec     eax
2458
        mov     ebp, [SECTORS_PER_CLUSTER]
2459
        imul    eax, ebp
2460
        add     eax, [DATA_START]
2461
; write data
2462
.write_sector:
321 diamond 2463
        cmp     byte [esp+16+32+28], 0
2464
        jnz     .writedir
83 diamond 2465
        mov     ecx, 512
2466
        cmp     dword [esp+8], ecx
2467
        jb      .writeshort
2468
; we can write directly from given buffer
2469
        mov     ebx, esi
2470
        add     esi, ecx
2471
        jmp     .writecommon
2472
.writeshort:
2473
        mov     ecx, [esp+8]
2474
        push    ecx
2475
        mov     edi, buffer
2476
        mov     ebx, edi
2477
        rep     movsb
321 diamond 2478
.writedircont:
83 diamond 2479
        mov     ecx, buffer+0x200
2480
        sub     ecx, edi
2481
        push    eax
2482
        xor     eax, eax
2483
        rep     stosb
2484
        pop     eax
2485
        pop     ecx
2486
.writecommon:
2487
        call    hd_write
2488
        cmp     [hd_error], 0
2489
        jnz     .writeerr
2490
        inc     eax
2491
        sub     dword [esp+8], ecx
2492
        jz      .writedone
2493
        dec     ebp
2494
        jnz     .write_sector
2495
; allocate new cluster
2496
        pop     eax
2497
        mov     ecx, eax
2498
        call    get_free_FAT
2499
        jc      .diskfull
2500
        push    edx
2501
        mov     edx, [fatEND]
2502
        call    set_FAT
2503
        xchg    eax, ecx
2504
        mov     edx, ecx
2505
        call    set_FAT
2506
        pop     edx
2507
        xchg    eax, ecx
2508
        jmp     .write_cluster
2509
.diskfull:
2510
        mov     eax, ERROR_DISK_FULL
2511
        jmp     .ret
2512
.writeerr:
2513
        pop     eax
2514
        sub     esi, ecx
2515
        mov     eax, 11
2516
        jmp     .ret
2517
.writedone:
2518
        pop     eax
2519
.done:
2520
        xor     eax, eax
2521
.ret:
2522
        pop     edi ecx
2523
        mov     ebx, esi
2524
        sub     ebx, edx
2525
        pop     ebp
2526
        mov     [esp+32+28], eax
2527
        lea     eax, [esp+8]
2528
        call    dword [eax+8]
2529
        mov     [edi+28], ebx
2530
        call    dword [eax+16]
2531
        mov     [esp+32+16], ebx
2532
        lea     eax, [ebx+511]
2533
        shr     eax, 9
2534
        mov     ecx, [SECTORS_PER_CLUSTER]
2535
        lea     eax, [eax+ecx-1]
2536
        xor     edx, edx
2537
        div     ecx
2538
        mov     ecx, ebp
2539
        sub     ecx, eax
2540
        call    add_disk_free_space
2541
        add     esp, 32
2542
        call    update_disk
2543
        popad
2544
        ret
321 diamond 2545
.writedir:
2546
        push    512
2547
        mov     edi, buffer
2548
        mov     ebx, edi
2549
        mov     ecx, [SECTORS_PER_CLUSTER]
2550
        shl     ecx, 9
2551
        cmp     ecx, [esp+12]
2552
        jnz     .writedircont
2553
        dec     dword [esp+16]
2554
        push    esi
2555
        mov     ecx, 32/4
2556
        rep     movsd
2557
        pop     esi
2558
        mov     dword [edi-32], '.   '
2559
        mov     dword [edi-32+4], '    '
2560
        mov     dword [edi-32+8], '    '
2561
        mov     byte [edi-32+11], 10h
2562
        push    esi
2563
        mov     ecx, 32/4
2564
        rep     movsd
2565
        pop     esi
2566
        mov     dword [edi-32], '..  '
2567
        mov     dword [edi-32+4], '    '
2568
        mov     dword [edi-32+8], '    '
2569
        mov     byte [edi-32+11], 10h
2570
        mov     ecx, [esp+20+8]
2571
        cmp     ecx, [ROOT_CLUSTER]
2572
        jnz     @f
2573
        xor     ecx, ecx
2574
@@:
2575
        mov     word [edi-32+26], cx
2576
        shr     ecx, 16
2577
        mov     [edi-32+20], cx
2578
        jmp     .writedircont
83 diamond 2579
 
131 diamond 2580
;----------------------------------------------------------------
2581
;
256 diamond 2582
;  fs_HdWrite - LFN variant for writing to hard disk
131 diamond 2583
;
2584
;  esi  points to filename
2585
;  ebx  pointer to 64-bit number = first wanted byte, 0+
2586
;       may be ebx=0 - start from first byte
2587
;  ecx  number of bytes to write, 0+
2588
;  edx  mem location to data
2589
;
2590
;  ret ebx = bytes written (maybe 0)
2591
;      eax = 0 ok write or other = errormsg
2592
;
2593
;--------------------------------------------------------------
2594
fs_HdWrite.access_denied:
2595
        push    ERROR_ACCESS_DENIED
2596
fs_HdWrite.ret0:
2597
        pop     eax
2598
        xor     ebx, ebx
2599
        ret
2600
 
2601
fs_HdWrite.ret11:
2602
        push    11
2603
        jmp     fs_HdWrite.ret0
2604
 
2605
fs_HdWrite:
256 diamond 2606
        cmp     [fs_type], 1
2607
        jz      ntfs_HdWrite
2608
        cmp     [fs_type], 16
2609
        jz      @f
2610
        cmp     [fs_type], 32
2611
        jz      @f
131 diamond 2612
        push    ERROR_UNKNOWN_FS
2613
        jmp     .ret0
2614
@@:
2615
        cmp     byte [esi], 0
2616
        jz      .access_denied
2617
        pushad
2618
        call    hd_find_lfn
2619
        pushfd
2620
        cmp     [hd_error], 0
2621
        jz      @f
2622
        popfd
2623
        popad
2624
        push    11
2625
        jmp     .ret0
2626
@@:
2627
        popfd
2628
        jnc     .found
2629
        popad
2630
        push    ERROR_FILE_NOT_FOUND
2631
        jmp     .ret0
2632
.found:
2633
; FAT does not support files larger than 4GB
2634
        test    ebx, ebx
2635
        jz      .l1
2636
        cmp     dword [ebx+4], 0
2637
        jz      @f
2638
.eof:
2639
        popad
2640
        push    ERROR_END_OF_FILE
2641
        jmp     .ret0
2642
@@:
2643
        mov     ebx, [ebx]
2644
.l1:
2645
; now edi points to direntry, ebx=start byte to write,
2646
; ecx=number of bytes to write, edx=data pointer
2647
 
2648
; extend file if needed
2649
        add     ecx, ebx
2650
        jc      .eof    ; FAT does not support files larger than 4GB
2651
        push    eax     ; save directory sector
2652
        push    0       ; return value=0
2653
 
2654
        call    get_time_for_file
2655
        mov     [edi+22], ax            ; last write time
2656
        call    get_date_for_file
2657
        mov     [edi+24], ax            ; last write date
2658
        mov     [edi+18], ax            ; last access date
2659
 
2660
        push    dword [edi+28]          ; save current file size
2661
        cmp     ecx, [edi+28]
2662
        jbe     .length_ok
2663
        cmp     ecx, ebx
2664
        jz      .length_ok
2665
        call    hd_extend_file
2666
        jnc     .length_ok
2667
        mov     [esp+4], eax
2668
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
2669
; First two cases are fatal errors, in third case we may write some data
2670
        cmp     al, ERROR_DISK_FULL
2671
        jz      .disk_full
2672
        pop     eax
2673
        pop     eax
2674
        mov     [esp+4+28], eax
2675
        pop     eax
2676
        popad
2677
        xor     ebx, ebx
2678
        ret
2679
.disk_full:
2680
; correct number of bytes to write
2681
        mov     ecx, [edi+28]
2682
        cmp     ecx, ebx
2683
        ja      .length_ok
2684
.ret:
2685
        call    update_disk
2686
        cmp     [hd_error], 0
2687
        jz      @f
2688
        mov     byte [esp+4], 11
2689
@@:
2690
        pop     eax
2691
        pop     eax
2692
        mov     [esp+4+28], eax ; eax=return value
2693
        pop     eax
2694
        sub     edx, [esp+20]
2695
        mov     [esp+16], edx   ; ebx=number of written bytes
2696
        popad
2697
        ret
2698
.length_ok:
2699
        mov     esi, [edi+28]
2700
        mov     eax, [edi+20-2]
2701
        mov     ax, [edi+26]
2702
        mov     edi, eax        ; edi=current cluster
2703
        xor     ebp, ebp        ; ebp=current sector in cluster
2704
; save directory
2705
        mov     eax, [esp+8]
2706
        push    ebx
2707
        mov     ebx, buffer
2708
        call    hd_write
2709
        pop     ebx
2710
        cmp     [hd_error], 0
2711
        jz      @f
2712
.device_err:
2713
        mov     byte [esp+4], 11
2714
        jmp     .ret
2715
@@:
2716
 
2717
; now ebx=start pos, ecx=end pos, both lie inside file
2718
        sub     ecx, ebx
2719
        jz      .ret
2720
.write_loop:
321 diamond 2721
; skip unmodified sectors
2722
        cmp     dword [esp], 0x200
2723
        jb      .modify
2724
        sub     ebx, 0x200
2725
        jae     .skip
2726
        add     ebx, 0x200
2727
.modify:
131 diamond 2728
; get length of data in current sector
2729
        push    ecx
2730
        sub     ebx, 0x200
2731
        jb      .hasdata
2732
        neg     ebx
2733
        xor     ecx, ecx
2734
        jmp     @f
2735
.hasdata:
2736
        neg     ebx
2737
        cmp     ecx, ebx
2738
        jbe     @f
2739
        mov     ecx, ebx
2740
@@:
2741
; get current sector number
2742
        mov     eax, edi
2743
        dec     eax
2744
        dec     eax
2745
        imul    eax, [SECTORS_PER_CLUSTER]
2746
        add     eax, [DATA_START]
2747
        add     eax, ebp
2748
; load sector if needed
2749
        cmp     dword [esp+4], 0        ; we don't need to read uninitialized data
2750
        jz      .noread
2751
        cmp     ecx, 0x200      ; we don't need to read sector if it is fully rewritten
2752
        jz      .noread
2753
        cmp     ecx, esi        ; (same for the last sector)
2754
        jz      .noread
2755
        push    ebx
2756
        mov     ebx, buffer
2757
        call    hd_read
2758
        pop     ebx
2759
        cmp     [hd_error], 0
2760
        jz      @f
2761
.device_err2:
2762
        pop     ecx
2763
        jmp     .device_err
2764
@@:
2765
.noread:
2766
; zero uninitialized data if file was extended (because hd_extend_file does not this)
2767
        push    eax ecx edi
2768
        xor     eax, eax
2769
        mov     ecx, 0x200
2770
        sub     ecx, [esp+4+12]
2771
        jbe     @f
2772
        mov     edi, buffer
2773
        add     edi, [esp+4+12]
2774
        rep     stosb
2775
@@:
2776
; zero uninitialized data in the last sector
2777
        mov     ecx, 0x200
2778
        sub     ecx, esi
2779
        jbe     @f
2780
        mov     edi, buffer
2781
        add     edi, esi
2782
        rep     stosb
2783
@@:
321 diamond 2784
        pop     edi ecx
131 diamond 2785
; copy new data
2786
        mov     eax, edx
2787
        neg     ebx
2788
        jecxz   @f
2789
        add     ebx, buffer+0x200
2790
        call    memmove
2791
        xor     ebx, ebx
2792
@@:
2793
        pop     eax
2794
; save sector
2795
        push    ebx
2796
        mov     ebx, buffer
2797
        call    hd_write
2798
        pop     ebx
2799
        cmp     [hd_error], 0
2800
        jnz     .device_err2
2801
        add     edx, ecx
2802
        sub     [esp], ecx
2803
        pop     ecx
2804
        jz      .ret
321 diamond 2805
.skip:
131 diamond 2806
; next sector
2807
        inc     ebp
2808
        cmp     ebp, [SECTORS_PER_CLUSTER]
2809
        jb      @f
2810
        xor     ebp, ebp
2811
        mov     eax, edi
2812
        call    get_FAT
2813
        mov     edi, eax
2814
        cmp     [hd_error], 0
2815
        jnz     .device_err
2816
@@:
2817
        sub     esi, 0x200
2818
        jae     @f
2819
        xor     esi, esi
2820
@@:
2821
        sub     dword [esp], 0x200
2822
        jae     @f
2823
        and     dword [esp], 0
2824
@@:     jmp     .write_loop
2825
 
2826
hd_extend_file.zero_size:
2827
        xor     eax, eax
2828
        jmp     hd_extend_file.start_extend
2829
 
2830
; extends file on hd to given size (new data area is undefined)
2831
; in: edi->direntry, ecx=new size
133 diamond 2832
; out: CF=0 => OK, eax=0
131 diamond 2833
;      CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL or 11)
2834
hd_extend_file:
2835
        push    ebp
2836
        mov     ebp, [SECTORS_PER_CLUSTER]
2837
        imul    ebp, [BYTES_PER_SECTOR]
2838
        push    ecx
2839
; find the last cluster of file
2840
        mov     eax, [edi+20-2]
2841
        mov     ax, [edi+26]
2842
        mov     ecx, [edi+28]
2843
        jecxz   .zero_size
2844
.last_loop:
2845
        sub     ecx, ebp
2846
        jbe     .last_found
2847
        call    get_FAT
2848
        cmp     [hd_error], 0
2849
        jz      @f
2850
.device_err:
2851
        pop     ecx
2852
.device_err2:
2853
        pop     ebp
2854
        push    11
2855
.ret_err:
2856
        pop     eax
2857
        stc
2858
        ret
2859
@@:
2860
        cmp     eax, 2
2861
        jb      .fat_err
2862
        cmp     eax, [fatRESERVED]
2863
        jb      .last_loop
2864
.fat_err:
2865
        pop     ecx ebp
2866
        push    ERROR_FAT_TABLE
2867
        jmp     .ret_err
2868
.last_found:
2869
        push    eax
2870
        call    get_FAT
2871
        cmp     [hd_error], 0
2872
        jz      @f
2873
        pop     eax
2874
        jmp     .device_err
2875
@@:
2876
        cmp     eax, [fatRESERVED]
2877
        pop     eax
2878
        jb      .fat_err
2879
; set length to full number of clusters
2880
        sub     [edi+28], ecx
2881
.start_extend:
2882
        pop     ecx
2883
; now do extend
2884
        push    edx
2885
        mov     edx, 2          ; start scan from cluster 2
2886
.extend_loop:
2887
        cmp     [edi+28], ecx
2888
        jae     .extend_done
2889
; add new cluster
2890
        push    eax
2891
        mov     eax, edx
2892
        call    get_free_FAT
2893
        jc      .disk_full
2894
        mov     edx, [fatEND]
2895
        call    set_FAT
2896
        mov     edx, eax
2897
        pop     eax
2898
        test    eax, eax
2899
        jz      .first_cluster
2900
        push    edx
2901
        call    set_FAT
2902
        pop     edx
2903
        jmp     @f
2904
.first_cluster:
2905
        ror     edx, 16
2906
        mov     [edi+20], dx
2907
        ror     edx, 16
2908
        mov     [edi+26], dx
2909
@@:
133 diamond 2910
        push    ecx
2911
        mov     ecx, -1
2912
        call    add_disk_free_space
2913
        pop     ecx
131 diamond 2914
        mov     eax, edx
2915
        cmp     [hd_error], 0
2916
        jnz     .device_err3
2917
        add     [edi+28], ebp
2918
        jmp     .extend_loop
2919
.extend_done:
2920
        mov     [edi+28], ecx
2921
        pop     edx ebp
133 diamond 2922
        xor     eax, eax        ; CF=0
131 diamond 2923
        ret
2924
.device_err3:
2925
        pop     edx
2926
        jmp     .device_err2
2927
.disk_full:
2928
        pop     eax edx ebp
2929
        push    ERROR_DISK_FULL
2930
        pop     eax
2931
        cmp     [hd_error], 0
2932
        jz      @f
2933
        mov     al, 11
2934
@@:     stc
2935
        ret
2936
 
133 diamond 2937
;----------------------------------------------------------------
2938
;
2939
;  fs_HdSetFileEnd - set end of file on hard disk
2940
;
2941
;  esi  points to filename
2942
;  ebx  points to 64-bit number = new file size
2943
;  ecx  ignored (reserved)
2944
;  edx  ignored (reserved)
2945
;
2946
;  ret eax = 0 ok or other = errormsg
2947
;
2948
;--------------------------------------------------------------
2949
fs_HdSetFileEnd:
256 diamond 2950
        cmp     [fs_type], 1
2951
        jz      ntfs_HdSetFileEnd
2952
        cmp     [fs_type], 16
2953
        jz      @f
2954
        cmp     [fs_type], 32
2955
        jz      @f
133 diamond 2956
        push    ERROR_UNKNOWN_FS
2957
.ret:
2958
        pop     eax
2959
        ret
2960
@@:
2961
        cmp     byte [esi], 0
2962
        jnz     @f
2963
.access_denied:
2964
        push    ERROR_ACCESS_DENIED
2965
        jmp     .ret
2966
@@:
2967
        push    edi
2968
        call    hd_find_lfn
2969
        pushfd
2970
        cmp     [hd_error], 0
2971
        jz      @f
2972
        popfd
2973
        push    11
2974
        jmp     .ret
2975
@@:
2976
        popfd
2977
        jnc     @f
2978
        pop     edi
2979
        push    ERROR_FILE_NOT_FOUND
2980
        jmp     .ret
2981
@@:
2982
; must not be directory
2983
        test    byte [edi+11], 10h
2984
        jz      @f
2985
        pop     edi
2986
        jmp     .access_denied
2987
@@:
2988
; file size must not exceed 4 Gb
2989
        cmp     dword [ebx+4], 0
2990
        jz      @f
2991
        pop     edi
2992
        push    ERROR_END_OF_FILE
2993
        jmp     .ret
2994
@@:
2995
        push    eax     ; save directory sector
2996
; set file modification date/time to current
2997
        call    fat_update_datetime
2998
        mov     eax, [ebx]
2999
        cmp     eax, [edi+28]
3000
        jb      .truncate
3001
        ja      .expand
3002
        pop     eax
3003
        mov     ebx, buffer
3004
        call    hd_write
3005
        pop     edi
3006
        xor     eax, eax
3007
        cmp     [hd_error], 0
3008
        jz      @f
3009
        mov     al, 11
3010
@@:
3011
        ret
3012
.expand:
3013
        push    ebx ebp ecx
3014
        push    dword [edi+28]  ; save old size
3015
        mov     ecx, eax
3016
        call    hd_extend_file
3017
        push    eax             ; return code
3018
        jnc     .expand_ok
3019
        cmp     al, ERROR_DISK_FULL
3020
        jz      .disk_full
3021
.pop_ret:
3022
        call    update_disk
3023
        pop     eax ecx ebp ebx ecx edi edi
3024
        ret
3025
.expand_ok:
3026
.disk_full:
3027
; save directory
3028
        mov     eax, [edi+28]
3029
        xchg    eax, [esp+20]
3030
        mov     ebx, buffer
3031
        call    hd_write
3032
        mov     eax, [edi+20-2]
3033
        mov     ax, [edi+26]
3034
        mov     edi, eax
3035
        cmp     [hd_error], 0
3036
        jz      @f
3037
.pop_ret11:
3038
        mov     byte [esp], 11
3039
        jmp     .pop_ret
3040
@@:
3041
; now zero new data
3042
        xor     ebp, ebp
3043
; edi=current cluster, ebp=sector in cluster
3044
; [esp+20]=new size, [esp+4]=old size, [esp]=return code
3045
.zero_loop:
3046
        sub     dword [esp+4], 0x200
3047
        jae     .next_cluster
3048
        lea     eax, [edi-2]
3049
        imul    eax, [SECTORS_PER_CLUSTER]
3050
        add     eax, [DATA_START]
3051
        add     eax, ebp
3052
        cmp     dword [esp+4], -0x200
3053
        jz      .noread
3054
        mov     ebx, buffer
3055
        call    hd_read
3056
        cmp     [hd_error], 0
3057
        jnz     .err_next
3058
.noread:
3059
        mov     ecx, [esp+4]
3060
        neg     ecx
3061
        push    edi
3062
        mov     edi, buffer+0x200
3063
        add     edi, [esp+8]
3064
        push    eax
3065
        xor     eax, eax
3066
        mov     [esp+12], eax
3067
        rep     stosb
3068
        pop     eax
3069
        pop     edi
3070
        call    hd_write
3071
        cmp     [hd_error], 0
3072
        jz      .next_cluster
3073
.err_next:
3074
        mov     byte [esp], 11
3075
.next_cluster:
3076
        sub     dword [esp+20], 0x200
3077
        jbe     .pop_ret
3078
        inc     ebp
3079
        cmp     ebp, [SECTORS_PER_CLUSTER]
3080
        jb      .zero_loop
3081
        xor     ebp, ebp
3082
        mov     eax, edi
3083
        call    get_FAT
3084
        mov     edi, eax
3085
        cmp     [hd_error], 0
3086
        jnz     .pop_ret11
3087
        jmp     .zero_loop
3088
.truncate:
3089
        mov     [edi+28], eax
3090
        push    ecx
3091
        mov     ecx, [edi+20-2]
3092
        mov     cx, [edi+26]
3093
        push    eax
3094
        test    eax, eax
3095
        jz      .zero_size
3096
; find new last cluster
3097
@@:
3098
        mov     eax, [SECTORS_PER_CLUSTER]
3099
        shl     eax, 9
3100
        sub     [esp], eax
3101
        jbe     @f
3102
        mov     eax, ecx
3103
        call    get_FAT
3104
        mov     ecx, eax
3105
        cmp     [hd_error], 0
3106
        jz      @b
3107
.device_err3:
3108
        pop     eax ecx eax edi
3109
        push    11
3110
        pop     eax
3111
        ret
3112
@@:
3113
; we will zero data at the end of last sector - remember it
3114
        push    ecx
3115
; terminate FAT chain
3116
        push    edx
3117
        mov     eax, ecx
3118
        mov     edx, [fatEND]
3119
        call    set_FAT
3120
        mov     eax, edx
3121
        pop     edx
3122
        cmp     [hd_error], 0
3123
        jz      @f
3124
.device_err4:
3125
        pop     ecx
3126
        jmp     .device_err3
3127
.zero_size:
3128
        and     word [edi+20], 0
3129
        and     word [edi+26], 0
3130
        push    0
3131
        mov     eax, ecx
3132
@@:
3133
; delete FAT chain
3134
        call    clear_cluster_chain
3135
        cmp     [hd_error], 0
3136
        jnz     .device_err4
3137
; save directory
3138
        mov     eax, [esp+12]
3139
        push    ebx
3140
        mov     ebx, buffer
3141
        call    hd_write
3142
        pop     ebx
3143
        cmp     [hd_error], 0
3144
        jnz     .device_err4
3145
; zero last sector, ignore errors
3146
        pop     ecx
3147
        pop     eax
3148
        dec     ecx
3149
        imul    ecx, [SECTORS_PER_CLUSTER]
3150
        add     ecx, [DATA_START]
3151
        push    eax
3152
        sar     eax, 9
3153
        add     ecx, eax
3154
        pop     eax
3155
        and     eax, 0x1FF
3156
        jz      .truncate_done
3157
        push    ebx eax
3158
        mov     eax, ecx
3159
        mov     ebx, buffer
3160
        call    hd_read
3161
        pop     eax
3162
        lea     edi, [buffer+eax]
3163
        push    ecx
3164
        mov     ecx, 0x200
3165
        sub     ecx, eax
3166
        xor     eax, eax
3167
        rep     stosb
3168
        pop     eax
3169
        call    hd_write
3170
        pop     ebx
3171
.truncate_done:
3172
        pop     ecx eax edi
3173
        call    update_disk
3174
        xor     eax, eax
3175
        cmp     [hd_error], 0
3176
        jz      @f
3177
        mov     al, 11
3178
@@:
3179
        ret
3180
 
86 diamond 3181
fs_HdGetFileInfo:
256 diamond 3182
        cmp     [fs_type], 1
3183
        jz      ntfs_HdGetFileInfo
3184
        cmp     [fs_type], 16
3185
        jz      @f
3186
        cmp     [fs_type], 32
3187
        jz      @f
86 diamond 3188
        mov     eax, ERROR_UNKNOWN_FS
3189
        ret
3190
@@:
3191
        cmp     byte [esi], 0
3192
        jnz     @f
3193
        mov     eax, 2
3194
        ret
3195
@@:
3196
        push    edi
3197
        call    hd_find_lfn
3198
        pushfd
3199
        cmp     [hd_error], 0
3200
        jz      @f
3201
        popfd
3202
        pop     edi
3203
        mov     eax, 11
3204
        ret
3205
@@:
3206
        popfd
3207
        jmp     fs_GetFileInfo_finish
3208
 
3209
fs_HdSetFileInfo:
256 diamond 3210
        cmp     [fs_type], 1
3211
        jz      ntfs_HdSetFileInfo
3212
        cmp     [fs_type], 16
3213
        jz      @f
3214
        cmp     [fs_type], 32
3215
        jz      @f
86 diamond 3216
        mov     eax, ERROR_UNKNOWN_FS
3217
        ret
3218
@@:
3219
        cmp     byte [esi], 0
3220
        jnz     @f
3221
        mov     eax, 2
3222
        ret
3223
@@:
3224
        push    edi
3225
        call    hd_find_lfn
3226
        pushfd
3227
        cmp     [hd_error], 0
3228
        jz      @f
3229
        popfd
3230
        pop     edi
3231
        mov     eax, 11
3232
        ret
3233
@@:
3234
        popfd
3235
        jnc     @f
3236
        pop     edi
3237
        mov     eax, ERROR_FILE_NOT_FOUND
3238
        ret
3239
@@:
3240
        push    eax
3241
        call    bdfe_to_fat_entry
3242
        pop     eax
3243
        mov     ebx, buffer
3244
        call    hd_write
3245
        call    update_disk
3246
        pop     edi
3247
        xor     eax, eax
3248
        ret
3249
 
256 diamond 3250
if 0    ; starting from revision 237 execute is implemented in taskman.inc
3251
        ; through fs_XxxGetFileInfo and fs_XxxRead
91 diamond 3252
;----------------------------------------------------------------
3253
;
3254
;  fs_HdExecute - LFN variant for executing from harddisk
3255
;
3256
;  esi  points to hd filename (e.g. 'dir1/name')
3257
;  ebp  points to full filename (e.g. '/hd0/1/dir1/name')
3258
;  dword [ebx] = flags
3259
;  dword [ebx+4] = cmdline
3260
;
3261
;  ret ebx,edx destroyed
3262
;      eax > 0 - PID, < 0 - error
3263
;
3264
;--------------------------------------------------------------
3265
fs_HdExecute:
3266
        mov     edx, [ebx]
3267
        mov     ebx, [ebx+4]
3268
        test    ebx, ebx
3269
        jz      @f
465 serge 3270
   ;     add     ebx, std_application_base_address
91 diamond 3271
@@:
3272
 
3273
;----------------------------------------------------------------
3274
;
3275
; fs_HdExecute.flags - second entry
3276
;
3277
;  esi  points to floppy filename (kernel address)
3278
;  ebp  points to full filename
3279
;  edx  flags
3280
;  ebx  cmdline (kernel address)
3281
;
3282
;  ret  eax > 0 - PID, < 0 - error
3283
;
3284
;--------------------------------------------------------------
3285
 
3286
.flags:
3287
        cmp     [fat_type], 0
3288
        jnz     @f
171 diamond 3289
        mov     eax, -ERROR_UNKNOWN_FS
91 diamond 3290
        ret
3291
@@:
3292
        cmp     byte [esi], 0
3293
        jnz     @f
3294
; cannot execute root!
3295
        mov     eax, -ERROR_ACCESS_DENIED
3296
        ret
3297
@@:
3298
        push    edi
3299
        call    hd_find_lfn
3300
        jnc     .found
3301
        pop     edi
3302
        mov     eax, -ERROR_FILE_NOT_FOUND
3303
        cmp     [hd_error], 0
3304
        jz      @f
3305
        mov     al, -11
3306
@@:
3307
        ret
3308
.found:
3309
        mov     eax, [edi+20-2]
3310
        mov     ax, [edi+26]
3311
        push    0
3312
        push    eax
3313
        push    dword [edi+28]          ; size
3314
        push    .DoRead
3315
        call    fs_execute
3316
        add     esp, 16
3317
        pop     edi
3318
        ret
3319
 
3320
.DoRead:
3321
; read next block
3322
; in: eax->parameters, edi->buffer
3323
; out: eax = error code
3324
        pushad
3325
        cmp     dword [eax], 0  ; file size
3326
        jz      .eof
3327
        add     eax, 4
3328
        call    fat_get_sector
3329
        mov     ebx, edi
3330
        call    hd_read
3331
        cmp     [hd_error], 0
3332
        jnz     .err
3333
        mov     eax, [esp+28]
3334
        mov     ecx, [eax]
3335
        sub     ecx, 512
3336
        jae     @f
3337
        lea     edi, [edi+ecx+512]
3338
        neg     ecx
3339
        push    eax
3340
        xor     eax, eax
3341
        rep     stosb
3342
        pop     eax
3343
@@:
3344
        mov     [eax], ecx
3345
        mov     edx, [eax+8]
3346
        inc     edx
3347
        cmp     edx, [SECTORS_PER_CLUSTER]
3348
        jb      @f
3349
        push    eax
3350
        mov     eax, [eax+4]
3351
        call    get_FAT
3352
        cmp     [hd_error], 0
3353
        jnz     .err
3354
        mov     ecx, eax
3355
        pop     eax
3356
        mov     [eax+4], ecx
3357
        xor     edx, edx
3358
@@:
3359
        mov     [eax+8], edx
3360
        popad
3361
        xor     eax, eax
3362
        ret
3363
.eof:
3364
        popad
3365
        mov     eax, 6
3366
        ret
3367
.err:
3368
        popad
3369
        mov     eax, 11
3370
        ret
256 diamond 3371
end if
91 diamond 3372
 
171 diamond 3373
;----------------------------------------------------------------
3374
;
3375
;  fs_HdDelete - delete file or empty folder from hard disk
3376
;
3377
;  esi  points to filename
3378
;
3379
;  ret  eax = 0 ok or other = errormsg
3380
;
3381
;--------------------------------------------------------------
3382
fs_HdDelete:
256 diamond 3383
        cmp     [fs_type], 1
3384
        jz      ntfs_HdDelete
3385
        cmp     [fs_type], 16
3386
        jz      @f
3387
        cmp     [fs_type], 32
3388
        jz      @f
171 diamond 3389
        push    ERROR_UNKNOWN_FS
3390
.pop_ret:
3391
        pop     eax
3392
        ret
3393
@@:
3394
        cmp     byte [esi], 0
3395
        jnz     @f
3396
; cannot delete root!
3397
.access_denied:
3398
        push    ERROR_ACCESS_DENIED
3399
        jmp     .pop_ret
3400
@@:
3401
        and     [longname_sec1], 0
3402
        and     [longname_sec2], 0
3403
        push    edi
3404
        call    hd_find_lfn
3405
        jnc     .found
3406
        pop     edi
3407
        push    ERROR_FILE_NOT_FOUND
3408
        jmp     .pop_ret
3409
.found:
3410
        cmp     dword [edi], '.   '
3411
        jz      .access_denied2
3412
        cmp     dword [edi], '..  '
3413
        jz      .access_denied2
3414
        test    byte [edi+11], 10h
3415
        jz      .dodel
3416
; we can delete only empty folders!
3417
        pushad
3418
        mov     ebp, [edi+20-2]
3419
        mov     bp, [edi+26]
3420
        xor     ecx, ecx
3421
        lea     eax, [ebp-2]
3422
        imul    eax, [SECTORS_PER_CLUSTER]
3423
        add     eax, [DATA_START]
3424
        mov     ebx, buffer
3425
        call    hd_read
3426
        cmp     [hd_error], 0
3427
        jnz     .err1
3428
        add     ebx, 2*0x20
3429
.checkempty:
3430
        cmp     byte [ebx], 0
3431
        jz      .empty
3432
        cmp     byte [ebx], 0xE5
3433
        jnz     .notempty
3434
        add     ebx, 0x20
3435
        cmp     ebx, buffer+0x200
3436
        jb      .checkempty
3437
        inc     ecx
3438
        cmp     ecx, [SECTORS_PER_CLUSTER]
3439
        jb      @f
3440
        mov     eax, ebp
3441
        call    get_FAT
3442
        cmp     [hd_error], 0
3443
        jnz     .err1
3444
        mov     ebp, eax
3445
        xor     ecx, ecx
3446
@@:
3447
        lea     eax, [ebp-2]
3448
        imul    eax, [SECTORS_PER_CLUSTER]
3449
        add     eax, [DATA_START]
3450
        add     eax, ecx
3451
        mov     ebx, buffer
3452
        call    hd_read
3453
        cmp     [hd_error], 0
3454
        jz      .checkempty
3455
.err1:
3456
        popad
3457
.err2:
3458
        pop     edi
3459
        push    11
3460
        pop     eax
3461
        ret
3462
.notempty:
3463
        popad
3464
.access_denied2:
3465
        pop     edi
3466
        push    ERROR_ACCESS_DENIED
3467
        pop     eax
3468
        ret
3469
.empty:
3470
        popad
3471
        push    ebx
3472
        mov     ebx, buffer
3473
        call    hd_read
3474
        pop     ebx
3475
        cmp     [hd_error], 0
3476
        jnz     .err2
3477
.dodel:
3478
        push    eax
3479
        mov     eax, [edi+20-2]
3480
        mov     ax, [edi+26]
3481
        xchg    eax, [esp]
3482
; delete folder entry
3483
        mov     byte [edi], 0xE5
3484
; delete LFN (if present)
3485
.lfndel:
3486
        cmp     edi, buffer
3487
        ja      @f
3488
        cmp     [longname_sec2], 0
3489
        jz      .lfndone
3490
        push    [longname_sec2]
3491
        push    [longname_sec1]
3492
        pop     [longname_sec2]
3493
        and     [longname_sec1], 0
3494
        push    ebx
3495
        mov     ebx, buffer
3496
        call    hd_write
3497
        mov     eax, [esp+4]
3498
        call    hd_read
3499
        pop     ebx
3500
        pop     eax
3501
        mov     edi, buffer+0x200
3502
@@:
3503
        sub     edi, 0x20
3504
        cmp     byte [edi], 0xE5
3505
        jz      .lfndone
3506
        cmp     byte [edi+11], 0xF
3507
        jnz     .lfndone
3508
        mov     byte [edi], 0xE5
3509
        jmp     .lfndel
3510
.lfndone:
3511
        push    ebx
3512
        mov     ebx, buffer
3513
        call    hd_write
3514
        pop     ebx
3515
; delete FAT chain
3516
        pop     eax
3517
        call    clear_cluster_chain
3518
        call    update_disk
3519
        pop     edi
3520
        xor     eax, eax
3521
        cmp     [hd_error], 0
3522
        jz      @f
3523
        mov     al, 11
3524
@@:
3525
        ret
3526
 
74 mario79 3527
; \end{diamond}