Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1159 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;; RAMDISK functions                                            ;;
7
;; (C) 2004 Ville Turjanmaa, License: GPL                       ;;
8
;; Addings by M.Lisovin                                         ;;
9
;; LFN support by diamond                                       ;;
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11
 
1206 hidnplayr 12
$Revision: 1206 $
1159 hidnplayr 13
 
14
 
15
; calculate fat chain
16
 
17
calculatefatchain:
18
 
19
   pushad
20
 
21
   mov	esi,RAMDISK+512
22
   mov	edi,RAMDISK_FAT
23
 
24
 fcnew:
25
   mov	eax,dword [esi]
26
   mov	ebx,dword [esi+4]
27
   mov	ecx,dword [esi+8]
28
   mov	edx,ecx
29
   shr	edx,4	;8 ok
30
   shr	dx,4	;7 ok
31
   xor	ch,ch
32
   shld ecx,ebx,20 ;6 ok
33
   shr	cx,4	 ;5 ok
34
   shld ebx,eax,12
35
   and	ebx,0x0fffffff	;4 ok
36
   shr	bx,4	;3 ok
37
   shl	eax,4
38
   and	eax,0x0fffffff	;2 ok
39
   shr	ax,4  ;1 ok
40
   mov	dword [edi],eax
41
   mov	dword [edi+4],ebx
42
   mov	dword [edi+8],ecx
43
   mov	dword [edi+12],edx
44
   add	edi,16
45
   add	esi,12
46
 
47
   cmp	edi,RAMDISK_FAT+2856*2	 ;2849 clusters
48
   jnz	fcnew
49
 
50
   popad
51
   ret
52
 
53
 
54
restorefatchain:   ; restore fat chain
55
 
56
   pushad
57
 
58
   mov	esi,RAMDISK_FAT
59
   mov	edi,RAMDISK+512
60
 
61
  fcnew2:
62
   mov	eax,dword [esi]
63
   mov	ebx,dword [esi+4]
64
   shl	ax,4
65
   shl	eax,4
66
   shl	bx,4
67
   shr	ebx,4
68
   shrd eax,ebx,8
69
   shr	ebx,8
70
   mov	dword [edi],eax
71
   mov	word [edi+4],bx
72
   add	edi,6
73
   add	esi,8
74
 
75
   cmp	edi,RAMDISK+512+4278	 ;4274 bytes - all used FAT
76
   jb	fcnew2
77
 
78
   mov	esi,RAMDISK+512 	  ; duplicate fat chain
79
   mov	edi,RAMDISK+512+0x1200
80
   mov	ecx,1069	;4274/4
81
   cld
82
   rep	movsd
83
 
84
   popad
85
   ret
86
 
87
 
88
ramdisk_free_space:
89
;---------------------------------------------
90
;
91
; returns free space in edi
92
; rewr.by Mihasik
93
;---------------------------------------------
94
 
95
	push   eax ebx ecx
96
 
97
	mov  edi,RAMDISK_FAT ;start of FAT
98
	xor  ax,ax    ;Free cluster=0x0000 in FAT
99
	xor  ebx,ebx  ;counter
100
	mov  ecx,2849 ;2849 clusters
101
	cld
102
    rdfs1:
103
	repne scasw
104
	jnz  rdfs2    ;if last cluster not 0
105
	inc  ebx
106
	test	ecx, ecx
107
	jnz	rdfs1
108
    rdfs2:
109
	shl  ebx,9    ;free clusters*512
110
	mov  edi,ebx
111
 
112
	pop    ecx ebx eax
113
	ret
114
 
115
 
116
expand_filename:
117
;---------------------------------------------
118
;
119
; exapand filename with '.' to 11 character
120
; eax - pointer to filename
121
;---------------------------------------------
122
 
123
	push esi edi ebx
124
 
125
	mov  edi,esp		      ; check for '.' in the name
126
	add  edi,12+8
127
 
128
	mov  esi,eax
129
 
130
	mov  eax,edi
131
	mov  [eax+0],dword '    '
132
	mov  [eax+4],dword '    '
133
	mov  [eax+8],dword '    '
134
 
135
      flr1:
136
 
137
	cmp  [esi],byte '.'
138
	jne  flr2
139
	mov  edi,eax
140
	add  edi,7
141
	jmp  flr3
142
 
143
      flr2:
144
 
145
	mov  bl,[esi]
146
	mov  [edi],bl
147
 
148
      flr3:
149
 
150
	inc  esi
151
	inc  edi
152
 
153
	mov  ebx,eax
154
	add  ebx,11
155
 
156
	cmp  edi,ebx
157
	jbe  flr1
158
 
159
	pop  ebx edi esi
160
	ret
161
 
162
fileread:
163
;----------------------------------------------------------------
164
;
165
;  fileread - sys floppy
166
;
167
;  eax  points to filename 11 chars
168
;  ebx  first wanted block       ; 1+ ; if 0 then set to 1
169
;  ecx  number of blocks to read ; 1+ ; if 0 then set to 1
170
;  edx  mem location to return data
171
;  esi  length of filename 12*X 0=root
172
;
173
;  ret ebx = size or 0xffffffff file not found
174
;      eax = 0 ok read or other = errormsg
175
;
176
;--------------------------------------------------------------
177
	test   ebx,ebx ;if ebx=0 - set to 1
178
	jnz    frfl5
179
	inc    ebx
180
      frfl5:
181
	test   ecx,ecx ;if ecx=0 - set to 1
182
	jnz    frfl6
183
	inc    ecx
184
      frfl6:
185
	test   esi,esi		; return ramdisk root
186
	jnz    fr_noroot	;if not root
187
	cmp    ebx,14		;14 clusters=root dir
188
	ja     oorr
189
	cmp    ecx,14
190
	ja     oorr
191
	jmp    fr_do
192
      oorr:
193
	mov    eax,5		;out of root range (fnf)
194
	xor    ebx,ebx
195
	dec    ebx		;0xffffffff
196
	ret
197
 
198
      fr_do:			;reading rootdir
199
	mov    edi,edx
200
	dec    ebx
201
	push   edx
202
	mov    edx,ecx
203
	add    edx,ebx
204
	cmp    edx,15	  ;ebx+ecx=14+1
205
	pushf
206
	jbe    fr_do1
207
	sub    edx,14
208
	sub    ecx,edx
209
      fr_do1:
210
	shl    ebx,9
211
	mov    esi,RAMDISK+512*19
212
	add    esi,ebx
213
	shl    ecx,7
214
	cld
215
	rep    movsd
216
	popf
217
	pop    edx
218
	jae    fr_do2
219
	xor    eax,eax ; ok read
220
	xor    ebx,ebx
221
	ret
222
      fr_do2:	     ;if last cluster
223
	mov    eax,6  ;end of file
224
	xor    ebx,ebx
225
	ret
226
 
227
     fr_noroot:
228
 
229
	sub    esp,32
230
	call   expand_filename
231
 
232
	dec    ebx
233
 
234
	push   eax
235
 
236
	push   eax ebx ecx edx esi edi
237
	call   rd_findfile
238
	je     fifound
239
	add    esp,32+28   ;if file not found
240
	ret
241
 
242
     fifound:
243
 
244
	mov    ebx,[edi-11+28]		;file size
245
	mov    [esp+20],ebx
246
	mov    [esp+24],ebx
247
	add    edi,0xf
248
	movzx  eax,word [edi]
249
	mov    edi,eax			;edi=cluster
250
 
251
      frnew:
252
 
253
	add    eax,31			;bootsector+2*fat+filenames
254
	shl    eax,9			;*512
255
	add    eax,RAMDISK	       ;image base
256
	mov    ebx,[esp+8]
257
	mov    ecx,512			;[esp+4]
258
 
259
	cmp    [esp+16],dword 0 	; wanted cluster ?
260
	jne    frfl7
261
	call   memmove
262
	add    [esp+8],dword 512
263
	dec    dword [esp+12]		; last wanted cluster ?
264
	je     frnoread
265
	jmp    frfl8
266
      frfl7:
267
	dec    dword [esp+16]
268
      frfl8:
269
	movzx  eax,word [edi*2+RAMDISK_FAT]	   ; find next cluster from FAT
270
	mov    edi,eax
271
	cmp    edi,4095 		;eof  - cluster
272
	jz     frnoread2
273
 
274
	cmp    [esp+24],dword 512	;eof  - size
275
	jb     frnoread
276
	sub    [esp+24],dword 512
277
 
278
	jmp    frnew
279
 
280
      frnoread2:
281
 
282
	cmp    [esp+16],dword 0 	; eof without read ?
283
	je     frnoread
284
 
285
	pop    edi esi edx ecx
286
	add    esp,4
287
	pop    ebx     ; ebx <- eax : size of file
288
	add    esp,36
289
	mov    eax,6   ; end of file
290
	ret
291
 
292
      frnoread:
293
 
294
	pop    edi esi edx ecx
295
	add    esp,4
296
	pop    ebx     ; ebx <- eax : size of file
297
	add    esp,36
298
	xor    eax,eax	;read ok
299
	ret
300
 
301
 
302
 
303
   rd_findfile:
304
   ;by Mihasik
305
   ;IN: eax - pointer to filename OUT: filestring+11 in edi or notZero in flags and fnf in eax,ebx
306
 
307
	mov    edi,RAMDISK+512*18+512  ;Point at directory
308
	cld
309
    rd_newsearch:
310
	mov    esi,eax
311
	mov    ecx,11
312
	rep    cmpsb
313
	je     rd_ff
314
	add    cl,21
315
	add    edi,ecx
316
	cmp    edi,RAMDISK+512*33
317
	jb     rd_newsearch
318
	mov    eax,5	  ;if file not found - eax=5
319
	xor    ebx,ebx
320
	dec    ebx    ;ebx=0xffffffff and zf=0
321
     rd_ff:
322
	ret
323
 
324
; \begin{diamond}
325
 
326
uni2ansi_str:
327
; convert UNICODE zero-terminated string to ASCII-string (codepage 866)
328
; in: esi->source, edi->buffer (may be esi=edi)
329
; destroys: eax,esi,edi
330
	lodsw
331
	test	ax, ax
332
	jz	.done
333
	cmp	ax, 0x80
334
	jb	.ascii
335
	cmp	ax, 0x401
336
	jz	.yo1
337
	cmp	ax, 0x451
338
	jz	.yo2
339
	cmp	ax, 0x410
340
	jb	.unk
341
	cmp	ax, 0x440
342
	jb	.rus1
343
	cmp	ax, 0x450
344
	jb	.rus2
345
.unk:
346
	mov	al, '_'
347
	jmp	.doit
348
.yo1:
349
	mov	al, 'ð'
350
	jmp	.doit
351
.yo2:
352
	mov	al, 'ñ'
353
	jmp	.doit
354
.rus1:
355
; 0x410-0x43F -> 0x80-0xAF
356
	add	al, 0x70
357
	jmp	.doit
358
.rus2:
359
; 0x440-0x44F -> 0xE0-0xEF
360
	add	al, 0xA0
361
.ascii:
362
.doit:
363
	stosb
364
	jmp	uni2ansi_str
365
.done:
366
	mov	byte [edi], 0
367
	ret
368
 
369
ansi2uni_char:
370
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
371
	mov	ah, 0
372
; 0x00-0x7F - trivial map
373
	cmp	al, 0x80
374
	jb	.ret
375
; 0x80-0xAF -> 0x410-0x43F
376
	cmp	al, 0xB0
377
	jae	@f
378
	add	ax, 0x410-0x80
379
.ret:
380
	ret
381
@@:
382
; 0xE0-0xEF -> 0x440-0x44F
383
	cmp	al, 0xE0
384
	jb	.unk
385
	cmp	al, 0xF0
386
	jae	@f
387
	add	ax, 0x440-0xE0
388
	ret
389
; 0xF0 -> 0x401
390
; 0xF1 -> 0x451
391
@@:
392
	cmp	al, 'ð'
393
	jz	.yo1
394
	cmp	al, 'ñ'
395
	jz	.yo2
396
.unk:
397
	mov	al, '_' 	; ah=0
398
	ret
399
.yo1:
400
	mov	ax, 0x401
401
	ret
402
.yo2:
403
	mov	ax, 0x451
404
	ret
405
 
406
char_toupper:
407
; convert character to uppercase, using cp866 encoding
408
; in: al=symbol
409
; out: al=converted symbol
410
	cmp	al, 'a'
411
	jb	.ret
412
	cmp	al, 'z'
413
	jbe	.az
414
	cmp	al, ' '
415
	jb	.ret
416
	cmp	al, 'à'
417
	jb	.rus1
418
	cmp	al, 'ï'
419
	ja	.ret
420
; 0xE0-0xEF -> 0x90-0x9F
421
	sub	al, 'à'-''
422
.ret:
423
	ret
424
.rus1:
425
; 0xA0-0xAF -> 0x80-0x8F
426
.az:
427
	and	al, not 0x20
428
	ret
429
 
430
fat_get_name:
431
; in: edi->FAT entry
432
; out: CF=1 - no valid entry
433
; else CF=0 and ebp->ASCIIZ-name
434
; (maximum length of filename is 255 (wide) symbols without trailing 0,
435
;  but implementation requires buffer 261 words)
436
; destroys eax
437
	cmp	byte [edi], 0
438
	jz	.no
439
	cmp	byte [edi], 0xE5
440
	jnz	@f
441
.no:
442
	stc
443
	ret
444
@@:
445
	cmp	byte [edi+11], 0xF
446
	jz	.longname
447
	test	byte [edi+11], 8
448
	jnz	.no
449
	push	ecx
450
	push	edi ebp
451
	test	byte [ebp-4], 1
452
	jnz	.unicode_short
453
 
454
	mov	eax, [edi]
455
	mov	ecx, [edi+4]
456
	mov	[ebp], eax
457
	mov	[ebp+4], ecx
458
 
459
	mov	ecx, 8
460
@@:
461
	cmp	byte [ebp+ecx-1], ' '
462
	loope	 @b
463
 
464
	mov	eax, [edi+8]
465
	cmp	al, ' '
466
	je	.done
467
	shl	eax, 8
468
	mov	al, '.'
469
 
470
	lea ebp, [ebp+ecx+1]
471
	mov	[ebp], eax
472
	mov	ecx, 3
473
@@:
474
	rol eax, 8
475
	cmp al, ' '
476
	jne .done
477
	loop   @b
478
	dec ebp
479
.done:
480
	and	byte [ebp+ecx+1], 0   ; CF=0
481
	pop	ebp edi ecx
482
	ret
483
.unicode_short:
484
	mov	ecx, 8
485
	push	ecx
486
@@:
487
	mov	al, [edi]
488
	inc	edi
489
	call	ansi2uni_char
490
	mov	[ebp], ax
491
	inc	ebp
492
	inc	ebp
493
	loop	@b
494
	pop	ecx
495
@@:
496
	cmp	word [ebp-2], ' '
497
	jnz	@f
498
	dec	ebp
499
	dec	ebp
500
	loop	@b
501
@@:
502
	mov	word [ebp], '.'
503
	inc	ebp
504
	inc	ebp
505
	mov	ecx, 3
506
	push	ecx
507
@@:
508
	mov	al, [edi]
509
	inc	edi
510
	call	ansi2uni_char
511
	mov	[ebp], ax
512
	inc	ebp
513
	inc	ebp
514
	loop	@b
515
	pop	ecx
516
@@:
517
	cmp	word [ebp-2], ' '
518
	jnz	@f
519
	dec	ebp
520
	dec	ebp
521
	loop	@b
522
	dec	ebp
523
	dec	ebp
524
@@:
525
	and	word [ebp], 0	; CF=0
526
	pop	ebp edi ecx
527
	ret
528
.longname:
529
; LFN
530
	mov	al, byte [edi]
531
	and	eax, 0x3F
532
	dec	eax
533
	cmp	al, 20
534
	jae	.no	; ignore invalid entries
535
	mov	word [ebp+260*2], 0	; force null-terminating for orphans
536
	imul	eax, 13*2
537
	add	ebp, eax
538
	test	byte [edi], 0x40
539
	jz	@f
540
	mov	word [ebp+13*2], 0
541
@@:
542
	push	eax
543
; now copy name from edi to ebp ...
544
	mov	eax, [edi+1]
545
	mov	[ebp], eax	; symbols 1,2
546
	mov	eax, [edi+5]
547
	mov	[ebp+4], eax	; 3,4
548
	mov	eax, [edi+9]
549
	mov	[ebp+8], ax	; 5
550
	mov	eax, [edi+14]
551
	mov	[ebp+10], eax	; 6,7
552
	mov	eax, [edi+18]
553
	mov	[ebp+14], eax	; 8,9
554
	mov	eax, [edi+22]
555
	mov	[ebp+18], eax	; 10,11
556
	mov	eax, [edi+28]
557
	mov	[ebp+22], eax	; 12,13
558
; ... done
559
	pop	eax
560
	sub	ebp, eax
561
	test	eax, eax
562
	jz	@f
563
; if this is not first entry, more processing required
564
	stc
565
	ret
566
@@:
567
; if this is first entry:
568
	test	byte [ebp-4], 1
569
	jnz	.ret
570
; buffer at ebp contains UNICODE name, convert it to ANSI
571
	push	esi edi
572
	mov	esi, ebp
573
	mov	edi, ebp
574
	call	uni2ansi_str
575
	pop	edi esi
576
.ret:
577
	clc
578
	ret
579
 
580
fat_compare_name:
581
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
582
; in: esi->name, ebp->name
583
; out: if names match: ZF=1 and esi->next component of name
584
;      else: ZF=0, esi is not changed
585
; destroys eax
586
	push	ebp esi
587
.loop:
588
	mov	al, [ebp]
589
	inc	ebp
590
	call	char_toupper
591
	push	eax
592
	lodsb
593
	call	char_toupper
594
	cmp	al, [esp]
595
	jnz	.done
596
	pop	eax
597
	test	al, al
598
	jnz	.loop
599
	dec	esi
600
	pop	eax
601
	pop	ebp
602
	xor	eax, eax	; set ZF flag
603
	ret
604
.done:
605
	cmp	al, '/'
606
	jnz	@f
607
	cmp	byte [esp], 0
608
	jnz	@f
609
	mov	[esp+4], esi
610
@@:
611
	pop	eax
612
	pop	esi ebp
613
	ret
614
 
615
fat_time_to_bdfe:
616
; in: eax=FAT time
617
; out: eax=BDFE time
618
	push	ecx edx
619
	mov	ecx, eax
620
	mov	edx, eax
621
	shr	eax, 11
622
	shl	eax, 16 ; hours
623
	and	edx, 0x1F
624
	add	edx, edx
625
	mov	al, dl	; seconds
626
	shr	ecx, 5
627
	and	ecx, 0x3F
628
	mov	ah, cl	; minutes
629
	pop	edx ecx
630
	ret
631
 
632
fat_date_to_bdfe:
633
	push	ecx edx
634
	mov	ecx, eax
635
	mov	edx, eax
636
	shr	eax, 9
637
	add	ax, 1980
638
	shl	eax, 16 ; year
639
	and	edx, 0x1F
640
	mov	al, dl	; day
641
	shr	ecx, 5
642
	and	ecx, 0xF
643
	mov	ah, cl	; month
644
	pop	edx ecx
645
	ret
646
 
647
bdfe_to_fat_time:
648
	push	edx
649
	mov	edx, eax
650
	shr	eax, 16
651
	and	dh, 0x3F
652
	shl	eax, 6
653
	or	al, dh
654
	shr	dl, 1
655
	and	dl, 0x1F
656
	shl	eax, 5
657
	or	al, dl
658
	pop	edx
659
	ret
660
 
661
bdfe_to_fat_date:
662
	push	edx
663
	mov	edx, eax
664
	shr	eax, 16
665
	sub	ax, 1980
666
	and	dh, 0xF
667
	shl	eax, 4
668
	or	al, dh
669
	and	dl, 0x1F
670
	shl	eax, 5
671
	or	al, dl
672
	pop	edx
673
	ret
674
 
675
fat_entry_to_bdfe:
676
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
677
; destroys eax
678
	mov	eax, [ebp-4]
679
	mov	[esi+4], eax	; ASCII/UNICODE name
680
fat_entry_to_bdfe2:
681
	movzx	eax, byte [edi+11]
682
	mov	[esi], eax	; attributes
683
	movzx	eax, word [edi+14]
684
	call	fat_time_to_bdfe
685
	mov	[esi+8], eax	; creation time
686
	movzx	eax, word [edi+16]
687
	call	fat_date_to_bdfe
688
	mov	[esi+12], eax	; creation date
689
	and	dword [esi+16], 0	; last access time is not supported on FAT
690
	movzx	eax, word [edi+18]
691
	call	fat_date_to_bdfe
692
	mov	[esi+20], eax	; last access date
693
	movzx	eax, word [edi+22]
694
	call	fat_time_to_bdfe
695
	mov	[esi+24], eax	; last write time
696
	movzx	eax, word [edi+24]
697
	call	fat_date_to_bdfe
698
	mov	[esi+28], eax	; last write date
699
	mov	eax, [edi+28]
700
	mov	[esi+32], eax	; file size (low dword)
701
	xor	eax, eax
702
	mov	[esi+36], eax	; file size (high dword)
703
	test	ebp, ebp
704
	jz	.ret
705
	push	ecx edi
706
	lea	edi, [esi+40]
707
	mov	esi, ebp
708
	test	byte [esi-4], 1
709
	jz	.ansi
710
	mov	ecx, 260/2
711
	rep	movsd
712
	mov	[edi-2], ax
713
@@:
714
	mov	esi, edi
715
	pop	edi ecx
716
.ret:
717
	ret
718
.ansi:
719
	mov	ecx, 264/4
720
	rep	movsd
721
	mov	[edi-1], al
722
	jmp	@b
723
 
724
bdfe_to_fat_entry:
725
; convert BDFE at edx to FAT entry at edi
726
; destroys eax
727
; attributes byte
728
	test	byte [edi+11], 8	; volume label?
729
	jnz	@f
730
	mov	al, [edx]
731
	and	al, 0x27
732
	and	byte [edi+11], 0x10
733
	or	byte [edi+11], al
734
@@:
735
	mov	eax, [edx+8]
736
	call	bdfe_to_fat_time
737
	mov	[edi+14], ax		; creation time
738
	mov	eax, [edx+12]
739
	call	bdfe_to_fat_date
740
	mov	[edi+16], ax		; creation date
741
	mov	eax, [edx+20]
742
	call	bdfe_to_fat_date
743
	mov	[edi+18], ax		; last access date
744
	mov	eax, [edx+24]
745
	call	bdfe_to_fat_time
746
	mov	[edi+22], ax		; last write time
747
	mov	eax, [edx+28]
748
	call	bdfe_to_fat_date
749
	mov	[edi+24], ax		; last write date
750
	ret
751
 
752
ramdisk_root_first:
753
	mov	edi, RAMDISK+512*19
754
	clc
755
	ret
756
ramdisk_root_next:
757
	add	edi, 0x20
758
	cmp	edi, RAMDISK+512*33
759
	cmc
760
	ret
761
 
762
ramdisk_root_extend_dir:
763
	stc
764
	ret
765
 
766
uglobal
767
; this is for delete support
768
rd_prev_sector		dd	?
769
rd_prev_prev_sector	dd	?
770
endg
771
 
772
ramdisk_notroot_next:
773
	add	edi, 0x20
774
	test	edi, 0x1FF
775
	jz	ramdisk_notroot_next_sector
776
	ret	; CF=0
777
ramdisk_notroot_next_sector:
778
	push	ecx
779
	mov	ecx, [eax]
780
	push	[rd_prev_sector]
781
	pop	[rd_prev_prev_sector]
782
	mov	[rd_prev_sector], ecx
783
	mov	ecx, [ecx*2+RAMDISK_FAT]
784
	and	ecx, 0xFFF
785
	cmp	ecx, 2849
786
	jae	ramdisk_notroot_first.err2
787
	mov	[eax], ecx
788
	pop	ecx
789
ramdisk_notroot_first:
790
	mov	eax, [eax]
791
	cmp	eax, 2
792
	jb	.err
793
	cmp	eax, 2849
794
	jae	.err
795
	shl	eax, 9
796
	lea	edi, [eax+(31 shl 9)+RAMDISK]
797
	clc
798
	ret
799
.err2:
800
	pop	ecx
801
.err:
802
	stc
803
	ret
804
ramdisk_notroot_next_write:
805
	test	edi, 0x1FF
806
	jz	ramdisk_notroot_next_sector
807
ramdisk_root_next_write:
808
	ret
809
 
810
ramdisk_notroot_extend_dir:
811
	pusha
812
	xor	eax, eax
813
	mov	edi, RAMDISK_FAT
814
	mov	ecx, 2849
815
	repnz	scasw
816
	jnz	.notfound
817
	mov	word [edi-2], 0xFFF
818
	sub	edi, RAMDISK_FAT
819
	shr	edi, 1
820
	dec	edi
821
	mov	eax, [esp+28]
822
	mov	ecx, [eax]
823
	mov	[RAMDISK_FAT+ecx*2], di
824
	mov	[eax], edi
825
	shl	edi, 9
826
	add	edi, (31 shl 9)+RAMDISK
827
	mov	[esp], edi
828
	xor	eax, eax
829
	mov	ecx, 128
830
	rep	stosd
831
	popa
832
	clc
833
	ret
834
.notfound:
835
	popa
836
	stc
837
	ret
838
 
839
rd_find_lfn:
840
; in: esi+ebp -> name
841
; out: CF=1 - file not found
842
;      else CF=0 and edi->direntry
843
	push	esi edi
844
	push	0
845
	push	ramdisk_root_first
846
	push	ramdisk_root_next
847
.loop:
848
	call	fat_find_lfn
849
	jc	.notfound
850
	cmp	byte [esi], 0
851
	jz	.found
852
.continue:
853
	test	byte [edi+11], 10h
854
	jz	.notfound
855
	movzx	eax, word [edi+26]
856
	mov	[esp+8], eax
857
	mov	dword [esp+4], ramdisk_notroot_first
858
	mov	dword [esp], ramdisk_notroot_next
859
	test	eax, eax
860
	jnz	.loop
861
	mov	dword [esp+4], ramdisk_root_first
862
	mov	dword [esp], ramdisk_notroot_next
863
	jmp	.loop
864
.notfound:
865
	add	esp, 12
866
	pop	edi esi
867
	stc
868
	ret
869
.found:
870
	test	ebp, ebp
871
	jz	@f
872
	mov	esi, ebp
873
	xor	ebp, ebp
874
	jmp	.continue
875
@@:
876
	mov	eax, [esp+8]
877
	add	esp, 16 	; CF=0
878
	pop	esi
879
	ret
880
 
881
;----------------------------------------------------------------
882
;
883
;  fs_RamdiskRead - LFN variant for reading sys floppy
884
;
885
;  esi  points to filename
886
;  ebx  pointer to 64-bit number = first wanted byte, 0+
887
;       may be ebx=0 - start from first byte
888
;  ecx  number of bytes to read, 0+
889
;  edx  mem location to return data
890
;
891
;  ret ebx = bytes read or 0xffffffff file not found
892
;      eax = 0 ok read or other = errormsg
893
;
894
;--------------------------------------------------------------
895
fs_RamdiskRead:
896
	cmp	byte [esi], 0
897
	jnz	@f
898
	or	ebx, -1
899
	mov	eax, 10 	; access denied
900
	ret
901
@@:
902
	push	edi
903
	call	rd_find_lfn
904
	jnc	.found
905
	pop	edi
906
	or	ebx, -1
907
	mov	eax, 5		; file not found
908
	ret
909
.found:
910
	test	ebx, ebx
911
	jz	.l1
912
	cmp	dword [ebx+4], 0
913
	jz	@f
914
	xor	ebx, ebx
915
.reteof:
916
	mov	eax, 6		; EOF
917
	pop	edi
918
	ret
919
@@:
920
	mov	ebx, [ebx]
921
.l1:
922
	push	ecx edx
923
	push	0
924
	mov	eax, [edi+28]
925
	sub	eax, ebx
926
	jb	.eof
927
	cmp	eax, ecx
928
	jae	@f
929
	mov	ecx, eax
930
	mov	byte [esp], 6		; EOF
931
@@:
932
	movzx	edi, word [edi+26]	; cluster
933
.new:
934
	jecxz	.done
935
	test	edi, edi
936
	jz	.eof
937
	cmp	edi, 0xFF8
938
	jae	.eof
939
	lea	eax, [edi+31]		; bootsector+2*fat+filenames
940
	shl	eax, 9			; *512
941
	add	eax, RAMDISK	       ; image base
942
; now eax points to data of cluster
943
	sub	ebx, 512
944
	jae	.skip
945
	lea	eax, [eax+ebx+512]
946
	neg	ebx
947
	push	ecx
948
	cmp	ecx, ebx
949
	jbe	@f
950
	mov	ecx, ebx
951
@@:
952
	mov	ebx, edx
953
	call	memmove
954
	add	edx, ecx
955
	sub	[esp], ecx
956
	pop	ecx
957
	xor	ebx, ebx
958
.skip:
959
	movzx	edi, word [edi*2+RAMDISK_FAT]	   ; find next cluster from FAT
960
	jmp	.new
961
.eof:
962
	mov	ebx, edx
963
	pop	eax edx ecx
964
	sub	ebx, edx
965
	jmp	.reteof
966
.done:
967
	mov	ebx, edx
968
	pop	eax edx ecx edi
969
	sub	ebx, edx
970
	ret
971
 
972
;----------------------------------------------------------------
973
;
974
;  fs_RamdiskReadFolder - LFN variant for reading sys floppy folder
975
;
976
;  esi  points to filename; only root is folder on ramdisk
977
;  ebx  pointer to structure 32-bit number = first wanted block
978
;                          & flags (bitfields)
979
; flags: bit 0: 0=ANSI names, 1=UNICODE names
980
;  ecx  number of blocks to read, 0+
981
;  edx  mem location to return data
982
;
983
;  ret ebx = size or 0xffffffff file not found
984
;      eax = 0 ok read or other = errormsg
985
;
986
;--------------------------------------------------------------
987
fs_RamdiskReadFolder:
988
	push	edi
989
	cmp	byte [esi], 0
990
	jz	.root
991
	call	rd_find_lfn
992
	jnc	.found
993
	pop	edi
994
	or	ebx, -1
995
	mov	eax, ERROR_FILE_NOT_FOUND
996
	ret
997
.found:
998
	test	byte [edi+11], 0x10
999
	jnz	.found_dir
1000
	pop	edi
1001
	or	ebx, -1
1002
	mov	eax, ERROR_ACCESS_DENIED
1003
	ret
1004
.found_dir:
1005
	movzx	eax, word [edi+26]
1006
	add	eax, 31
1007
	push	0
1008
	jmp	.doit
1009
.root:
1010
	mov	eax, 19
1011
	push	14
1012
.doit:
1013
	push	esi ecx ebp
1014
	sub	esp, 262*2	; reserve space for LFN
1015
	mov	ebp, esp
1016
	push	dword [ebx+4]	; for fat_get_name: read ANSI/UNICODE names
1017
	mov	ebx, [ebx]
1018
; init header
1019
	push	eax ecx
1020
	mov	edi, edx
1021
	mov	ecx, 32/4
1022
	xor	eax, eax
1023
	rep	stosd
1024
	mov	byte [edx], 1	; version
1025
	pop	ecx eax
1026
	mov	esi, edi	; esi points to block of data of folder entry (BDFE)
1027
.main_loop:
1028
	mov	edi, eax
1029
	shl	edi, 9
1030
	add	edi, RAMDISK
1031
	push	eax
1032
.l1:
1033
	call	fat_get_name
1034
	jc	.l2
1035
	cmp	byte [edi+11], 0xF
1036
	jnz	.do_bdfe
1037
	add	edi, 0x20
1038
	test	edi, 0x1FF
1039
	jnz	.do_bdfe
1040
	pop	eax
1041
	inc	eax
1042
	dec	byte [esp+262*2+16]
1043
	jz	.done
1044
	jns	@f
1045
; read next sector from FAT
1046
	mov	eax, [(eax-31-1)*2+RAMDISK_FAT]
1047
	and	eax, 0xFFF
1048
	cmp	eax, 0xFF8
1049
	jae	.done
1050
	add	eax, 31
1051
	mov	byte [esp+262*2+16], 0
1052
@@:
1053
	mov	edi, eax
1054
	shl	edi, 9
1055
	add	edi, RAMDISK
1056
	push	eax
1057
.do_bdfe:
1058
	inc	dword [edx+8]	; new file found
1059
	dec	ebx
1060
	jns	.l2
1061
	dec	ecx
1062
	js	.l2
1063
	inc	dword [edx+4]  ; new file block copied
1064
	call	fat_entry_to_bdfe
1065
.l2:
1066
	add	edi, 0x20
1067
	test	edi, 0x1FF
1068
	jnz	.l1
1069
	pop	eax
1070
	inc	eax
1071
	dec	byte [esp+262*2+16]
1072
	jz	.done
1073
	jns	@f
1074
; read next sector from FAT
1075
	mov	eax, [(eax-31-1)*2+RAMDISK_FAT]
1076
	and	eax, 0xFFF
1077
	cmp	eax, 0xFF8
1078
	jae	.done
1079
	add	eax, 31
1080
	mov	byte [esp+262*2+16], 0
1081
@@:
1082
	jmp	.main_loop
1083
.done:
1084
	add	esp, 262*2+4
1085
	pop	ebp
1086
	mov	ebx, [edx+4]
1087
	xor	eax, eax
1088
	dec	ecx
1089
	js	@f
1090
	mov	al, ERROR_END_OF_FILE
1091
@@:
1092
	pop	ecx esi edi edi
1093
	ret
1094
 
1095
iglobal
1096
label fat_legal_chars byte
1097
; 0 = not allowed
1098
; 1 = allowed only in long names
1099
; 3 = allowed
1100
	times 32 db 0
1101
;                 ! " # $ % & ' ( ) * + , - . /
1102
	db	1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
1103
;               0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1104
	db	3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
1105
;               @ A B C D E F G H I J K L M N O
1106
	db	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
1107
;               P Q R S T U V W X Y Z [ \ ] ^ _
1108
	db	3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
1109
;               ` a b c d e f g h i j k l m n o
1110
	db	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
1111
;               p q r s t u v w x y z { | } ~
1112
	db	3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
1113
endg
1114
 
1115
fat_name_is_legal:
1116
; in: esi->(long) name
1117
; out: CF set <=> legal
1118
; destroys eax
1119
	push	esi
1120
	xor	eax, eax
1121
@@:
1122
	lodsb
1123
	test	al, al
1124
	jz	.done
1125
	cmp	al, 80h
1126
	jae	.big
1127
	test	[fat_legal_chars+eax], 1
1128
	jnz	@b
1129
.err:
1130
	pop	esi
1131
	clc
1132
	ret
1133
.big:
1134
; 0x80-0xAF, 0xE0-0xEF
1135
	cmp	al, 0xB0
1136
	jb	@b
1137
	cmp	al, 0xE0
1138
	jb	.err
1139
	cmp	al, 0xF0
1140
	jb	@b
1141
	jmp	.err
1142
.done:
1143
	sub	esi, [esp]
1144
	cmp	esi, 257
1145
	pop	esi
1146
	ret
1147
 
1148
fat_next_short_name:
1149
; in: edi->8+3 name
1150
; out: name corrected
1151
;      CF=1 <=> error
1152
	pushad
1153
	mov	ecx, 8
1154
	mov	al, '~'
1155
	std
1156
	push	edi
1157
	add	edi, 7
1158
	repnz	scasb
1159
	pop	edi
1160
	cld
1161
	jz	.tilde
1162
; tilde is not found, insert "~1" at end
1163
	add	edi, 6
1164
	cmp	word [edi], '  '
1165
	jnz	.insert_tilde
1166
@@:	dec	edi
1167
	cmp	byte [edi], ' '
1168
	jz	@b
1169
	inc	edi
1170
.insert_tilde:
1171
	mov	word [edi], '~1'
1172
	popad
1173
	clc
1174
	ret
1175
.tilde:
1176
	push	edi
1177
	add	edi, 7
1178
	xor	ecx, ecx
1179
@@:
1180
; after tilde may be only digits and trailing spaces
1181
	cmp	byte [edi], '~'
1182
	jz	.break
1183
	cmp	byte [edi], ' '
1184
	jz	.space
1185
	cmp	byte [edi], '9'
1186
	jnz	.found
1187
	dec	edi
1188
	jmp	@b
1189
.space:
1190
	dec	edi
1191
	inc	ecx
1192
	jmp	@b
1193
.found:
1194
	inc	byte [edi]
1195
	add	dword [esp], 8
1196
	jmp	.zerorest
1197
.break:
1198
	jecxz	.noplace
1199
	inc	edi
1200
	mov	al, '1'
1201
@@:
1202
	xchg	al, [edi]
1203
	inc	edi
1204
	cmp	al, ' '
1205
	mov	al, '0'
1206
	jnz	@b
1207
.succ:
1208
	pop	edi
1209
	popad
1210
	clc
1211
	ret
1212
.noplace:
1213
	dec	edi
1214
	cmp	edi, [esp]
1215
	jz	.err
1216
	add	dword [esp], 8
1217
	mov	word [edi], '~1'
1218
	inc	edi
1219
	inc	edi
1220
@@:
1221
	mov	byte [edi], '0'
1222
.zerorest:
1223
	inc	edi
1224
	cmp	edi, [esp]
1225
	jb	@b
1226
	pop	edi
1227
	popad
1228
	;clc    ; automatically
1229
	ret
1230
.err:
1231
	pop	edi
1232
	popad
1233
	stc
1234
	ret
1235
 
1236
fat_gen_short_name:
1237
; in: esi->long name
1238
;     edi->buffer (8+3=11 chars)
1239
; out: buffer filled
1240
	pushad
1241
	mov	eax, '    '
1242
	push	edi
1243
	stosd
1244
	stosd
1245
	stosd
1246
	pop	edi
1247
	xor	eax, eax
1248
	push	8
1249
	pop	ebx
1250
	lea	ecx, [edi+8]
1251
.loop:
1252
	lodsb
1253
	test	al, al
1254
	jz	.done
1255
	call	char_toupper
1256
	cmp	al, ' '
1257
	jz	.space
1258
	cmp	al, 80h
1259
	ja	.big
1260
	test	[fat_legal_chars+eax], 2
1261
	jnz	.symbol
1262
.inv_symbol:
1263
	mov	al, '_'
1264
	or	bh, 1
1265
.symbol:
1266
	cmp	al, '.'
1267
	jz	.dot
1268
.normal_symbol:
1269
	dec	bl
1270
	jns	.store
1271
	mov	bl, 0
1272
.space:
1273
	or	bh, 1
1274
	jmp	.loop
1275
.store:
1276
	stosb
1277
	jmp	.loop
1278
.big:
1279
	cmp	al, 0xB0
1280
	jb	.normal_symbol
1281
	cmp	al, 0xE0
1282
	jb	.inv_symbol
1283
	cmp	al, 0xF0
1284
	jb	.normal_symbol
1285
	jmp	.inv_symbol
1286
.dot:
1287
	test	bh, 2
1288
	jz	.firstdot
1289
	pop	ebx
1290
	add	ebx, edi
1291
	sub	ebx, ecx
1292
	push	ebx
1293
	cmp	ebx, ecx
1294
	jb	@f
1295
	pop	ebx
1296
	push	ecx
1297
@@:
1298
	cmp	edi, ecx
1299
	jbe	.skip
1300
@@:
1301
	dec	edi
1302
	mov	al, [edi]
1303
	dec	ebx
1304
	mov	[ebx], al
1305
	mov	byte [edi], ' '
1306
	cmp	edi, ecx
1307
	ja	@b
1308
.skip:
1309
	mov	bh, 3
1310
	jmp	@f
1311
.firstdot:
1312
	cmp	bl, 8
1313
	jz	.space
1314
	push	edi
1315
	or	bh, 2
1316
@@:
1317
	mov	edi, ecx
1318
	mov	bl, 3
1319
	jmp	.loop
1320
.done:
1321
	test	bh, 2
1322
	jz	@f
1323
	pop	edi
1324
@@:
1325
	lea	edi, [ecx-8]
1326
	test	bh, 1
1327
	jz	@f
1328
	call	fat_next_short_name
1329
@@:
1330
	popad
1331
	ret
1332
 
1333
;----------------------------------------------------------------
1334
;
1335
;  fs_RamdiskRewrite - LFN variant for writing ramdisk
1336
;  fs_RamdiskCreateFolder - create folder on ramdisk
1337
;
1338
;  esi  points to file/folder name
1339
;  ebx  ignored (reserved)
1340
;  ecx  number of bytes to write, 0+ (ignored for folders)
1341
;  edx  mem location to data (ignored for folders)
1342
;
1343
;  ret ebx = number of written bytes
1344
;      eax = 0 ok read or other = errormsg
1345
;
1346
;--------------------------------------------------------------
1347
@@:
1348
	mov	eax, ERROR_ACCESS_DENIED
1349
	xor	ebx, ebx
1350
	ret
1351
 
1352
fs_RamdiskCreateFolder:
1353
	mov	al, 1		; create folder
1354
	jmp	fs_RamdiskRewrite.common
1355
 
1356
fs_RamdiskRewrite:
1357
	xor	eax, eax	; create file
1358
.common:
1359
	cmp	byte [esi], 0
1360
	jz	@b
1361
	pushad
1362
	xor	edi, edi
1363
	push	esi
1364
	test	ebp, ebp
1365
	jz	@f
1366
	mov	esi, ebp
1367
@@:
1368
	lodsb
1369
	test	al, al
1370
	jz	@f
1371
	cmp	al, '/'
1372
	jnz	@b
1373
	lea	edi, [esi-1]
1374
	jmp	@b
1375
@@:
1376
	pop	esi
1377
	test	edi, edi
1378
	jnz	.noroot
1379
	test	ebp, ebp
1380
	jnz	.hasebp
1381
	push	ramdisk_root_extend_dir
1382
	push	ramdisk_root_next_write
1383
	push	edi
1384
	push	ramdisk_root_first
1385
	push	ramdisk_root_next
1386
	jmp	.common1
1387
.hasebp:
1388
	mov	eax, ERROR_ACCESS_DENIED
1389
	cmp	byte [ebp], 0
1390
	jz	.ret1
1391
	push	ebp
1392
	xor	ebp, ebp
1393
	call	rd_find_lfn
1394
	pop	esi
1395
	jc	.notfound0
1396
	jmp	.common0
1397
.noroot:
1398
	mov	eax, ERROR_ACCESS_DENIED
1399
	cmp	byte [edi+1], 0
1400
	jz	.ret1
1401
; check existence
1402
	mov	byte [edi], 0
1403
	push	edi
1404
	call	rd_find_lfn
1405
	pop	esi
1406
	mov	byte [esi], '/'
1407
	jnc	@f
1408
.notfound0:
1409
	mov	eax, ERROR_FILE_NOT_FOUND
1410
.ret1:
1411
	mov	[esp+28], eax
1412
	popad
1413
	xor	ebx, ebx
1414
	ret
1415
@@:
1416
	inc	esi
1417
.common0:
1418
	test	byte [edi+11], 0x10	; must be directory
1419
	mov	eax, ERROR_ACCESS_DENIED
1420
	jz	.ret1
1421
	movzx	ebp, word [edi+26]	; ebp=cluster
1422
	mov	eax, ERROR_FAT_TABLE
1423
	cmp	ebp, 2
1424
	jb	.ret1
1425
	cmp	ebp, 2849
1426
	jae	.ret1
1427
	push	ramdisk_notroot_extend_dir
1428
	push	ramdisk_notroot_next_write
1429
	push	ebp
1430
	push	ramdisk_notroot_first
1431
	push	ramdisk_notroot_next
1432
.common1:
1433
	call	fat_find_lfn
1434
	jc	.notfound
1435
; found
1436
	test	byte [edi+11], 10h
1437
	jz	.exists_file
1438
; found directory; if we are creating directory, return OK,
1439
;                  if we are creating file, say "access denied"
1440
	add	esp, 20
1441
	popad
1442
	test	al, al
1443
	mov	eax, ERROR_ACCESS_DENIED
1444
	jz	@f
1445
	mov	al, 0
1446
@@:
1447
	xor	ebx, ebx
1448
	ret
1449
.exists_file:
1450
; found file; if we are creating directory, return "access denied",
1451
;             if we are creating file, delete existing file and continue
1452
	cmp	byte [esp+20+28], 0
1453
	jz	@f
1454
	add	esp, 20
1455
	popad
1456
	mov	eax, ERROR_ACCESS_DENIED
1457
	xor	ebx, ebx
1458
	ret
1459
@@:
1460
; delete FAT chain
1461
	push	edi
1462
	xor	eax, eax
1463
	mov	dword [edi+28], eax	; zero size
1464
	xchg	ax, word [edi+26]	; start cluster
1465
	test	eax, eax
1466
	jz	.done1
1467
@@:
1468
	cmp	eax, 0xFF8
1469
	jae	.done1
1470
	lea	edi, [RAMDISK_FAT + eax*2] ; position in FAT
1471
	xor	eax, eax
1472
	xchg	ax, [edi]
1473
	jmp	@b
1474
.done1:
1475
	pop	edi
1476
	call	get_time_for_file
1477
	mov	[edi+22], ax
1478
	call	get_date_for_file
1479
	mov	[edi+24], ax
1480
	mov	[edi+18], ax
1481
	or	byte [edi+11], 20h	; set 'archive' attribute
1482
	jmp	.doit
1483
.notfound:
1484
; file is not found; generate short name
1485
	call	fat_name_is_legal
1486
	jc	@f
1487
	add	esp, 20
1488
	popad
1489
	mov	eax, ERROR_FILE_NOT_FOUND
1490
	xor	ebx, ebx
1491
	ret
1492
@@:
1493
	sub	esp, 12
1494
	mov	edi, esp
1495
	call	fat_gen_short_name
1496
.test_short_name_loop:
1497
	push	esi edi ecx
1498
	mov	esi, edi
1499
	lea	eax, [esp+12+12+8]
1500
	mov	[eax], ebp
1501
	call	dword [eax-4]
1502
	jc	.found
1503
.test_short_name_entry:
1504
	cmp	byte [edi+11], 0xF
1505
	jz	.test_short_name_cont
1506
	mov	ecx, 11
1507
	push	esi edi
1508
	repz	cmpsb
1509
	pop	edi esi
1510
	jz	.short_name_found
1511
.test_short_name_cont:
1512
	lea	eax, [esp+12+12+8]
1513
	call	dword [eax-8]
1514
	jnc	.test_short_name_entry
1515
	jmp	.found
1516
.short_name_found:
1517
	pop	ecx edi esi
1518
	call	fat_next_short_name
1519
	jnc	.test_short_name_loop
1520
.disk_full:
1521
	add	esp, 12+20
1522
	popad
1523
	mov	eax, ERROR_DISK_FULL
1524
	xor	ebx, ebx
1525
	ret
1526
.found:
1527
	pop	ecx edi esi
1528
; now find space in directory
1529
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
1530
	mov	al, '~'
1531
	push	ecx edi
1532
	mov	ecx, 8
1533
	repnz	scasb
1534
	push	1
1535
	pop	eax	; 1 entry
1536
	jnz	.notilde
1537
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
1538
	xor	eax, eax
1539
@@:
1540
	cmp	byte [esi], 0
1541
	jz	@f
1542
	inc	esi
1543
	inc	eax
1544
	jmp	@b
1545
@@:
1546
	sub	esi, eax
1547
	add	eax, 12+13
1548
	mov	ecx, 13
1549
	push	edx
1550
	cdq
1551
	div	ecx
1552
	pop	edx
1553
.notilde:
1554
	push	-1
1555
	push	-1
1556
; find  successive entries in directory
1557
	xor	ecx, ecx
1558
	push	eax
1559
	lea	eax, [esp+12+8+12+8]
1560
	mov	[eax], ebp
1561
	call	dword [eax-4]
1562
	pop	eax
1563
.scan_dir:
1564
	cmp	byte [edi], 0
1565
	jz	.free
1566
	cmp	byte [edi], 0xE5
1567
	jz	.free
1568
	xor	ecx, ecx
1569
.scan_cont:
1570
	push	eax
1571
	lea	eax, [esp+12+8+12+8]
1572
	call	dword [eax-8]
1573
	pop	eax
1574
	jnc	.scan_dir
1575
	push	eax
1576
	lea	eax, [esp+12+8+12+8]
1577
	call	dword [eax+8]		; extend directory
1578
	pop	eax
1579
	jnc	.scan_dir
1580
	add	esp, 8+8+12+20
1581
	popad
1582
	mov	eax, ERROR_DISK_FULL
1583
	xor	ebx, ebx
1584
	ret
1585
.free:
1586
	test	ecx, ecx
1587
	jnz	@f
1588
	mov	[esp], edi
1589
	mov	ecx, [esp+8+8+12+8]
1590
	mov	[esp+4], ecx
1591
	xor	ecx, ecx
1592
@@:
1593
	inc	ecx
1594
	cmp	ecx, eax
1595
	jb	.scan_cont
1596
; found!
1597
; calculate name checksum
1598
	push	esi ecx
1599
	mov	esi, [esp+8+8]
1600
	mov	ecx, 11
1601
	xor	eax, eax
1602
@@:
1603
	ror	al, 1
1604
	add	al, [esi]
1605
	inc	esi
1606
	loop	@b
1607
	pop	ecx esi
1608
	pop	edi
1609
	pop	dword [esp+8+12+8]
1610
; edi points to last entry in free chunk
1611
	dec	ecx
1612
	jz	.nolfn
1613
	push	esi
1614
	push	eax
1615
	mov	al, 40h
1616
.writelfn:
1617
	or	al, cl
1618
	mov	esi, [esp+4]
1619
	push	ecx
1620
	dec	ecx
1621
	imul	ecx, 13
1622
	add	esi, ecx
1623
	stosb
1624
	mov	cl, 5
1625
	call	.read_symbols
1626
	mov	ax, 0xF
1627
	stosw
1628
	mov	al, [esp+4]
1629
	stosb
1630
	mov	cl, 6
1631
	call	.read_symbols
1632
	xor	eax, eax
1633
	stosw
1634
	mov	cl, 2
1635
	call	.read_symbols
1636
	pop	ecx
1637
	lea	eax, [esp+8+8+12+8]
1638
	call	dword [eax+4]	; next write
1639
	xor	eax, eax
1640
	loop	.writelfn
1641
	pop	eax
1642
	pop	esi
1643
.nolfn:
1644
	xchg	esi, [esp]
1645
	mov	ecx, 11
1646
	rep	movsb
1647
	mov	word [edi], 20h 	; attributes
1648
	sub	edi, 11
1649
	pop	esi ecx
1650
	add	esp, 12
1651
	mov	byte [edi+13], 0	; tenths of a second at file creation time
1652
	call	get_time_for_file
1653
	mov	[edi+14], ax		; creation time
1654
	mov	[edi+22], ax		; last write time
1655
	call	get_date_for_file
1656
	mov	[edi+16], ax		; creation date
1657
	mov	[edi+24], ax		; last write date
1658
	mov	[edi+18], ax		; last access date
1659
	and	word [edi+20], 0	; high word of cluster
1660
	and	word [edi+26], 0	; low word of cluster - to be filled
1661
	and	dword [edi+28], 0	; file size - to be filled
1662
	cmp	byte [esp+20+28], 0
1663
	jz	.doit
1664
; create directory
1665
	mov	byte [edi+11], 10h	   ; attributes: folder
1666
	mov	ecx, 32*2
1667
	mov	edx, edi
1668
.doit:
1669
	push	edx
1670
	push	ecx
1671
	push	edi
1672
	add	edi, 26 	; edi points to low word of cluster
1673
	push	edi
1674
	jecxz	.done
1675
	mov	ecx, 2849
1676
	mov	edi, RAMDISK_FAT
1677
.write_loop:
1678
; allocate new cluster
1679
	xor	eax, eax
1680
	repnz	scasw
1681
	jnz	.disk_full2
1682
	dec	edi
1683
	dec	edi
1684
 
1685
    ;    lea     eax, [edi-(RAMDISK_FAT)]
1686
 
1687
	mov eax, edi
1688
	sub eax, RAMDISK_FAT
1689
 
1690
	shr	eax, 1			; eax = cluster
1691
	mov	word [edi], 0xFFF	; mark as last cluster
1692
	xchg	edi, [esp]
1693
	stosw
1694
	pop	edi
1695
	push	edi
1696
	inc	ecx
1697
; write data
1698
	cmp	byte [esp+16+20+28], 0
1699
	jnz	.writedir
1700
	shl	eax, 9
1701
	add	eax, RAMDISK+31*512
1702
.writefile:
1703
	mov	ebx, edx
1704
	xchg	eax, ebx
1705
	push	ecx
1706
	mov	ecx, 512
1707
	cmp	dword [esp+12], ecx
1708
	jae	@f
1709
	mov	ecx, [esp+12]
1710
@@:
1711
	call	memmove
1712
	add	edx, ecx
1713
	sub	[esp+12], ecx
1714
	pop	ecx
1715
	jnz	.write_loop
1716
.done:
1717
	mov	ebx, edx
1718
	pop	edi edi ecx edx
1719
	sub	ebx, edx
1720
	mov	[edi+28], ebx
1721
	add	esp, 20
1722
	mov	[esp+16], ebx
1723
	popad
1724
	xor	eax, eax
1725
	ret
1726
.disk_full2:
1727
	mov	ebx, edx
1728
	pop	edi edi ecx edx
1729
	sub	ebx, edx
1730
	mov	[edi+28], ebx
1731
	add	esp, 20
1732
	mov	[esp+16], ebx
1733
	popad
1734
	push	ERROR_DISK_FULL
1735
	pop	eax
1736
	ret
1737
.writedir:
1738
	mov	edi, eax
1739
	shl	edi, 9
1740
	add	edi, RAMDISK+31*512
1741
	mov	esi, edx
1742
	mov	ecx, 32/4
1743
	push	ecx
1744
	rep	movsd
1745
	mov	dword [edi-32], '.   '
1746
	mov	dword [edi-32+4], '    '
1747
	mov	dword [edi-32+8], '    '
1748
	mov	byte [edi-32+11], 10h
1749
	mov	word [edi-32+26], ax
1750
	mov	esi, edx
1751
	pop	ecx
1752
	rep	movsd
1753
	mov	dword [edi-32], '..  '
1754
	mov	dword [edi-32+4], '    '
1755
	mov	dword [edi-32+8], '    '
1756
	mov	byte [edi-32+11], 10h
1757
	mov	eax, [esp+16+8]
1758
	mov	word [edi-32+26], ax
1759
	xor	eax, eax
1760
	mov	ecx, (512-32*2)/4
1761
	rep	stosd
1762
	pop	edi edi ecx edx
1763
	add	esp, 20
1764
	popad
1765
	xor	eax, eax
1766
	xor	ebx, ebx
1767
	ret
1768
 
1769
.read_symbol:
1770
	or	ax, -1
1771
	test	esi, esi
1772
	jz	.retFFFF
1773
	lodsb
1774
	test	al, al
1775
	jnz	ansi2uni_char
1776
	xor	eax, eax
1777
	xor	esi, esi
1778
.retFFFF:
1779
	ret
1780
 
1781
.read_symbols:
1782
	call	.read_symbol
1783
	stosw
1784
	loop	.read_symbols
1785
	ret
1786
 
1787
;----------------------------------------------------------------
1788
;
1789
;  fs_RamdiskWrite - LFN variant for writing to sys floppy
1790
;
1791
;  esi  points to filename
1792
;  ebx  pointer to 64-bit number = first wanted byte, 0+
1793
;       may be ebx=0 - start from first byte
1794
;  ecx  number of bytes to write, 0+
1795
;  edx  mem location to data
1796
;
1797
;  ret ebx = bytes written (maybe 0)
1798
;      eax = 0 ok write or other = errormsg
1799
;
1800
;--------------------------------------------------------------
1801
@@:
1802
	push	ERROR_ACCESS_DENIED
1803
fs_RamdiskWrite.ret0:
1804
	pop	eax
1805
	xor	ebx, ebx
1806
	ret
1807
 
1808
fs_RamdiskWrite:
1809
	cmp	byte [esi], 0
1810
	jz	@b
1811
	pushad
1812
	call	rd_find_lfn
1813
	jnc	.found
1814
	popad
1815
	push	ERROR_FILE_NOT_FOUND
1816
	jmp	.ret0
1817
.found:
1818
; must not be directory
1819
	test	byte [edi+11], 10h
1820
	jz	@f
1821
	popad
1822
	push	ERROR_ACCESS_DENIED
1823
	jmp	.ret0
1824
@@:
1825
; FAT does not support files larger than 4GB
1826
	test	ebx, ebx
1827
	jz	.l1
1828
	cmp	dword [ebx+4], 0
1829
	jz	@f
1830
.eof:
1831
	popad
1832
	push	ERROR_END_OF_FILE
1833
	jmp	.ret0
1834
@@:
1835
	mov	ebx, [ebx]
1836
.l1:
1837
; now edi points to direntry, ebx=start byte to write,
1838
; ecx=number of bytes to write, edx=data pointer
1839
	call	fat_update_datetime
1840
 
1841
; extend file if needed
1842
	add	ecx, ebx
1843
	jc	.eof	; FAT does not support files larger than 4GB
1844
	push	0	; return value=0
1845
	cmp	ecx, [edi+28]
1846
	jbe	.length_ok
1847
	cmp	ecx, ebx
1848
	jz	.length_ok
1849
	call	ramdisk_extend_file
1850
	jnc	.length_ok
1851
; ramdisk_extend_file can return two error codes: FAT table error or disk full.
1852
; First case is fatal error, in second case we may write some data
1853
	mov	[esp], eax
1854
	cmp	al, ERROR_DISK_FULL
1855
	jz	.disk_full
1856
	pop	eax
1857
	mov	[esp+28], eax
1858
	popad
1859
	xor	ebx, ebx
1860
	ret
1861
.disk_full:
1862
; correct number of bytes to write
1863
	mov	ecx, [edi+28]
1864
	cmp	ecx, ebx
1865
	ja	.length_ok
1866
.ret:
1867
	pop	eax
1868
	mov	[esp+28], eax	; eax=return value
1869
	sub	edx, [esp+20]
1870
	mov	[esp+16], edx	; ebx=number of written bytes
1871
	popad
1872
	ret
1873
.length_ok:
1874
; now ebx=start pos, ecx=end pos, both lie inside file
1875
	sub	ecx, ebx
1876
	jz	.ret
1877
	movzx	edi, word [edi+26]	; starting cluster
1878
.write_loop:
1879
	sub	ebx, 0x200
1880
	jae	.next_cluster
1881
	push	ecx
1882
	neg	ebx
1883
	cmp	ecx, ebx
1884
	jbe	@f
1885
	mov	ecx, ebx
1886
@@:
1887
	mov	eax, edi
1888
	shl	eax, 9
1889
	add	eax, RAMDISK+31*512+0x200
1890
	sub	eax, ebx
1891
	mov	ebx, eax
1892
	mov	eax, edx
1893
	call	memmove
1894
	xor	ebx, ebx
1895
	add	edx, ecx
1896
	sub	[esp], ecx
1897
	pop	ecx
1898
	jz	.ret
1899
.next_cluster:
1900
	movzx	edi, word [edi*2+RAMDISK_FAT]
1901
	jmp	.write_loop
1902
 
1903
ramdisk_extend_file.zero_size:
1904
	xor	eax, eax
1905
	jmp	ramdisk_extend_file.start_extend
1906
 
1907
; extends file on ramdisk to given size, new data area is filled by 0
1908
; in: edi->direntry, ecx=new size
1909
; out: CF=0 => OK, eax=0
1910
;      CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL)
1911
ramdisk_extend_file:
1912
	push	ecx
1913
; find the last cluster of file
1914
	movzx	eax, word [edi+26]	; first cluster
1915
	mov	ecx, [edi+28]
1916
	jecxz	.zero_size
1917
@@:
1918
	sub	ecx, 0x200
1919
	jbe	@f
1920
	mov	eax, [eax*2+RAMDISK_FAT]
1921
	and	eax, 0xFFF
1922
	jz	.fat_err
1923
	cmp	eax, 0xFF8
1924
	jb	@b
1925
.fat_err:
1926
	pop	ecx
1927
	push	ERROR_FAT_TABLE
1928
	pop	eax
1929
	stc
1930
	ret
1931
@@:
1932
	push	eax
1933
	mov	eax, [eax*2+RAMDISK_FAT]
1934
	and	eax, 0xFFF
1935
	cmp	eax, 0xFF8
1936
	pop	eax
1937
	jb	.fat_err
1938
; set length to full number of sectors and make sure that last sector is zero-padded
1939
	sub	[edi+28], ecx
1940
	push	eax edi
1941
	mov	edi, eax
1942
	shl	edi, 9
1943
	lea	edi, [edi+RAMDISK+31*512+0x200+ecx]
1944
	neg	ecx
1945
	xor	eax, eax
1946
	rep	stosb
1947
	pop	edi eax
1948
.start_extend:
1949
	pop	ecx
1950
; now do extend
1951
	push	edx esi
1952
	mov	esi, RAMDISK_FAT+2*2	   ; start scan from cluster 2
1953
	mov	edx, 2847		; number of clusters to scan
1954
.extend_loop:
1955
	cmp	[edi+28], ecx
1956
	jae	.extend_done
1957
; add new sector
1958
	push	ecx
1959
	mov	ecx, edx
1960
	push	edi
1961
	mov	edi, esi
1962
	jecxz	.disk_full
1963
	push	eax
1964
	xor	eax, eax
1965
	repnz	scasw
1966
	pop	eax
1967
	jnz	.disk_full
1968
	mov	word [edi-2], 0xFFF
1969
	mov	esi, edi
1970
	mov	edx, ecx
1971
	sub	edi, RAMDISK_FAT
1972
	shr	edi, 1
1973
	dec	edi	; now edi=new cluster
1974
	test	eax, eax
1975
	jz	.first_cluster
1976
	mov	[RAMDISK_FAT+eax*2], di
1977
	jmp	@f
1978
.first_cluster:
1979
	pop	eax	; eax->direntry
1980
	push	eax
1981
	mov	[eax+26], di
1982
@@:
1983
	push	edi
1984
	shl	edi, 9
1985
	add	edi, RAMDISK+31*512
1986
	xor	eax, eax
1987
	mov	ecx, 512/4
1988
	rep	stosd
1989
	pop	eax	; eax=new cluster
1990
	pop	edi	; edi->direntry
1991
	pop	ecx	; ecx=required size
1992
	add	dword [edi+28], 0x200
1993
	jmp	.extend_loop
1994
.extend_done:
1995
	mov	[edi+28], ecx
1996
	pop	esi edx
1997
	xor	eax, eax	; CF=0
1998
	ret
1999
.disk_full:
2000
	pop	edi ecx
2001
	pop	esi edx
2002
	stc
2003
	push	ERROR_DISK_FULL
2004
	pop	eax
2005
	ret
2006
 
2007
fat_update_datetime:
2008
	call	get_time_for_file
2009
	mov	[edi+22], ax		; last write time
2010
	call	get_date_for_file
2011
	mov	[edi+24], ax		; last write date
2012
	mov	[edi+18], ax		; last access date
2013
	ret
2014
 
2015
;----------------------------------------------------------------
2016
;
2017
;  fs_RamdiskSetFileEnd - set end of file on ramdisk
2018
;
2019
;  esi  points to filename
2020
;  ebx  points to 64-bit number = new file size
2021
;  ecx  ignored (reserved)
2022
;  edx  ignored (reserved)
2023
;
2024
;  ret eax = 0 ok or other = errormsg
2025
;
2026
;--------------------------------------------------------------
2027
fs_RamdiskSetFileEnd:
2028
	cmp	byte [esi], 0
2029
	jnz	@f
2030
.access_denied:
2031
	push	ERROR_ACCESS_DENIED
2032
	jmp	.ret
2033
@@:
2034
	push	edi
2035
	call	rd_find_lfn
2036
	jnc	@f
2037
	pop	edi
2038
	push	ERROR_FILE_NOT_FOUND
2039
.ret:
2040
	pop	eax
2041
	ret
2042
@@:
2043
; must not be directory
2044
	test	byte [edi+11], 10h
2045
	jz	@f
2046
	pop	edi
2047
	jmp	.access_denied
2048
@@:
2049
; file size must not exceed 4Gb
2050
	cmp	dword [ebx+4], 0
2051
	jz	@f
2052
	pop	edi
2053
	push	ERROR_END_OF_FILE
2054
	jmp	.ret
2055
@@:
2056
; set file modification date/time to current
2057
	call	fat_update_datetime
2058
	mov	eax, [ebx]
2059
	cmp	eax, [edi+28]
2060
	jb	.truncate
2061
	ja	.expand
2062
	pop	edi
2063
	xor	eax, eax
2064
	ret
2065
.expand:
2066
	push	ecx
2067
	mov	ecx, eax
2068
	call	ramdisk_extend_file
2069
	pop	ecx
2070
	pop	edi
2071
	ret
2072
.truncate:
2073
	mov	[edi+28], eax
2074
	push	ecx
2075
	movzx	ecx, word [edi+26]
2076
	test	eax, eax
2077
	jz	.zero_size
2078
; find new last sector
2079
@@:
2080
	sub	eax, 0x200
2081
	jbe	@f
2082
	movzx	ecx, word [RAMDISK_FAT+ecx*2]
2083
	jmp	@b
2084
@@:
2085
; zero data at the end of last sector
2086
	push	ecx
2087
	mov	edi, ecx
2088
	shl	edi, 9
2089
	lea	edi, [edi+RAMDISK+31*512+eax+0x200]
2090
	mov	ecx, eax
2091
	neg	ecx
2092
	xor	eax, eax
2093
	rep	stosb
2094
	pop	ecx
2095
; terminate FAT chain
2096
	lea	ecx, [RAMDISK_FAT+ecx+ecx]
2097
	push	dword [ecx]
2098
	mov	word [ecx], 0xFFF
2099
	pop	ecx
2100
	and	ecx, 0xFFF
2101
	jmp	.delete
2102
.zero_size:
2103
	and	word [edi+26], 0
2104
.delete:
2105
; delete FAT chain starting with ecx
2106
; mark all clusters as free
2107
	cmp	ecx, 0xFF8
2108
	jae	.deleted
2109
	lea	ecx, [RAMDISK_FAT+ecx+ecx]
2110
	push	dword [ecx]
2111
	and	word [ecx], 0
2112
	pop	ecx
2113
	and	ecx, 0xFFF
2114
	jmp	.delete
2115
.deleted:
2116
	pop	ecx
2117
	pop	edi
2118
	xor	eax, eax
2119
	ret
2120
 
2121
fs_RamdiskGetFileInfo:
2122
	cmp	byte [esi], 0
2123
	jnz	@f
2124
	mov	eax, 2	; unsupported
2125
	ret
2126
@@:
2127
	push	edi
2128
	call	rd_find_lfn
2129
fs_GetFileInfo_finish:
2130
	jnc	@f
2131
	pop	edi
2132
	mov	eax, ERROR_FILE_NOT_FOUND
2133
	ret
2134
@@:
2135
	push	esi ebp
2136
	xor	ebp, ebp
2137
	mov	esi, edx
2138
	and	dword [esi+4], 0
2139
	call	fat_entry_to_bdfe2
2140
	pop	ebp esi
2141
	pop	edi
2142
	xor	eax, eax
2143
	ret
2144
 
2145
fs_RamdiskSetFileInfo:
2146
	cmp	byte [esi], 0
2147
	jnz	@f
2148
	mov	eax, 2	; unsupported
2149
	ret
2150
@@:
2151
	push	edi
2152
	call	rd_find_lfn
2153
	jnc	@f
2154
	pop	edi
2155
	mov	eax, ERROR_FILE_NOT_FOUND
2156
	ret
2157
@@:
2158
	call	bdfe_to_fat_entry
2159
	pop	edi
2160
	xor	eax, eax
2161
	ret
2162
 
2163
;----------------------------------------------------------------
2164
;
2165
;  fs_RamdiskDelete - delete file or empty folder from ramdisk
2166
;
2167
;  esi  points to filename
2168
;
2169
;  ret  eax = 0 ok or other = errormsg
2170
;
2171
;--------------------------------------------------------------
2172
fs_RamdiskDelete:
2173
	cmp	byte [esi], 0
2174
	jnz	@f
2175
; cannot delete root!
2176
.access_denied:
2177
	push	ERROR_ACCESS_DENIED
2178
.pop_ret:
2179
	pop	eax
2180
	ret
2181
@@:
2182
	and	[rd_prev_sector], 0
2183
	and	[rd_prev_prev_sector], 0
2184
	push	edi
2185
	call	rd_find_lfn
2186
	jnc	.found
2187
	pop	edi
2188
	push	ERROR_FILE_NOT_FOUND
2189
	jmp	.pop_ret
2190
.found:
2191
	cmp	dword [edi], '.   '
2192
	jz	.access_denied2
2193
	cmp	dword [edi], '..  '
2194
	jz	.access_denied2
2195
	test	byte [edi+11], 10h
2196
	jz	.dodel
2197
; we can delete only empty folders!
2198
	movzx	eax, word [edi+26]
2199
	push	ebx
2200
	mov	ebx, eax
2201
	shl	ebx, 9
2202
	add	ebx, RAMDISK + 31*0x200 + 2*0x20
2203
.checkempty:
2204
	cmp	byte [ebx], 0
2205
	jz	.empty
2206
	cmp	byte [ebx], 0xE5
2207
	jnz	.notempty
2208
	add	ebx, 0x20
2209
	test	ebx, 0x1FF
2210
	jnz	.checkempty
2211
	movzx	eax, word [RAMDISK_FAT + eax*2]
2212
	test	eax, eax
2213
	jz	.empty
2214
	mov	ebx, eax
2215
	shl	ebx, 9
2216
	add	ebx, RAMDISK + 31*0x200
2217
	jmp	.checkempty
2218
.notempty:
2219
	pop	ebx
2220
.access_denied2:
2221
	pop	edi
2222
	jmp	.access_denied
2223
.empty:
2224
	pop	ebx
2225
.dodel:
2226
	movzx	eax, word [edi+26]
2227
; delete folder entry
2228
	mov	byte [edi], 0xE5
2229
; delete LFN (if present)
2230
.lfndel:
2231
	test	edi, 0x1FF
2232
	jnz	@f
2233
	cmp	[rd_prev_sector], 0
2234
	jz	@f
2235
	cmp	[rd_prev_sector], -1
2236
	jz	.lfndone
2237
	mov	edi, [rd_prev_sector]
2238
	push	[rd_prev_prev_sector]
2239
	pop	[rd_prev_sector]
2240
	or	[rd_prev_prev_sector], -1
2241
	shl	edi, 9
2242
	add	edi, RAMDISK + 31*0x200 + 0x200
2243
@@:
2244
	sub	edi, 0x20
2245
	cmp	byte [edi], 0xE5
2246
	jz	.lfndone
2247
	cmp	byte [edi+11], 0xF
2248
	jnz	.lfndone
2249
	mov	byte [edi], 0xE5
2250
	jmp	.lfndel
2251
.lfndone:
2252
; delete FAT chain
2253
	test	eax, eax
2254
	jz	.done
2255
	lea	eax, [RAMDISK_FAT + eax*2]
2256
	push	dword [eax]
2257
	and	word [eax], 0
2258
	pop	eax
2259
	and	eax, 0xFFF
2260
	jmp	.lfndone
2261
.done:
2262
	pop	edi
2263
	xor	eax, eax
2264
	ret
2265
 
2266
; \end{diamond}