Subversion Repositories Kolibri OS

Rev

Rev 3539 | Rev 4273 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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