Subversion Repositories Kolibri OS

Rev

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

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