Subversion Repositories Kolibri OS

Rev

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

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