Subversion Repositories Kolibri OS

Rev

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