Subversion Repositories Kolibri OS

Rev

Rev 7003 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
  4. ;;  Distributed under terms of the GNU General Public License.  ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 7136 $
  9.  
  10. ; FAT external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> FAT structure
  14. ; esi -> path string in UTF-8
  15. ;   out:
  16. ; eax, ebx = return values for sysfunc 70
  17. iglobal
  18. align 4
  19. fat_user_functions:
  20.         dd      fat_free
  21.         dd      (fat_user_functions_end - fat_user_functions - 4) / 4
  22.         dd      fat_Read
  23.         dd      fat_ReadFolder
  24.         dd      fat_CreateFile
  25.         dd      fat_Write
  26.         dd      fat_SetFileEnd
  27.         dd      fat_GetFileInfo
  28.         dd      fat_SetFileInfo
  29.         dd      0
  30.         dd      fat_Delete
  31.         dd      fat_CreateFolder
  32.         dd      fat_Rename
  33. fat_user_functions_end:
  34. endg
  35.  
  36. cache_max = 1919      ; max. is 1919*512+0x610000=0x6ffe00
  37.  
  38. PUSHAD_EAX equ [esp+28]
  39. PUSHAD_ECX equ [esp+24]
  40. PUSHAD_EDX equ [esp+20]
  41. PUSHAD_EBX equ [esp+16]
  42. PUSHAD_EBP equ [esp+8]
  43. PUSHAD_ESI equ [esp+4]
  44. PUSHAD_EDI equ [esp+0]
  45.  
  46. ; Internal data for every FAT partition.
  47. struct FAT PARTITION
  48. fs_type             db  ?
  49. fat_change          db  ?   ; 1=fat has changed
  50. createOption        db  ?
  51.                     rb  1
  52. Lock                MUTEX   ; currently operations with one partition
  53. ; can not be executed in parallel since the legacy code is not ready
  54. SECTORS_PER_FAT     dd  ?
  55. NUMBER_OF_FATS      dd  ?
  56. SECTORS_PER_CLUSTER dd  ?
  57. BYTES_PER_SECTOR    dd  ?   ; Note: if BPS <> 512 need lots of changes
  58. ROOT_CLUSTER        dd  ?   ; first rootdir cluster
  59. FAT_START           dd  ?   ; start of fat table
  60. ROOT_START          dd  ?   ; start of rootdir (only fat16)
  61. ROOT_SECTORS        dd  ?   ; count of rootdir sectors (only fat16)
  62. DATA_START          dd  ?   ; start of data area (=first cluster 2)
  63. LAST_CLUSTER        dd  ?   ; last availabe cluster
  64. ADR_FSINFO          dd  ?   ; used only by fat32
  65. fatRESERVED         dd  ?
  66. fatBAD              dd  ?
  67. fatEND              dd  ?
  68. fatMASK             dd  ?
  69. fatStartScan        dd  ?
  70. cluster_tmp         dd  ?   ; used by analyze_directory and analyze_directory_to_write
  71. longname_sec1       dd  ?   ; used by analyze_directory to save 2 previous
  72. longname_sec2       dd  ?   ; directory sectors for delete long filename
  73. fat_in_cache        dd  ?
  74. ; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT.
  75. ; For FAT12, the entire FAT structure is read
  76. ; and unpacked from 12bit per cluster to word per cluster.
  77. ; Note: work with unpacked copy of FAT12 means
  78. ; additional memory and additional code for packing/unpacking.
  79. ; I'm not sure that the economy justifies the cost, but anyway,
  80. ; there is how work was done before my edits, and I'm just keeping the principle.
  81. fat_cache_ptr       dd  ?
  82. fat12_unpacked_ptr  dd  ?
  83. volumeLabel         rb  12
  84. buffer              rb  512
  85. fsinfo_buffer       rb  512
  86. ends
  87.  
  88. uglobal
  89. align 4
  90. partition_count     dd  ?   ; partitions found by set_FAT32_variables
  91. hd_error            dd  ?
  92. hd_setup            dd  ?
  93. hd_wait_timeout     dd  ?
  94. cache_search_start  dd  ?   ; used by find_empty_slot
  95. Sector512:      ; label for dev_hdcd.inc
  96. buffer:
  97. rb 512
  98. endg
  99.  
  100. ; these labels are located before the main function to make
  101. ; most of jumps to these be short
  102. fat_create_partition.free_return0:
  103.         mov     eax, ebp
  104.         call    free
  105.         pop     ebp
  106. fat_create_partition.return0:
  107.         xor     eax, eax
  108.         ret
  109.  
  110. fat_create_partition:
  111.         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
  112.         jnz     .return0
  113. ; bootsector must have been successfully read
  114.         cmp     dword [esp+4], 0
  115.         jnz     .return0
  116. ; bootsector signature must be correct
  117.         cmp     word [ebx+0x1fe], 0xaa55
  118.         jnz     .return0
  119. ; sectors per cluster must be nonzero
  120.         cmp     byte [ebx+0xd], 0
  121.         jz      .return0
  122. ; bytes per sector must be 0x200
  123.         cmp     word [ebx+0xb], 0x200
  124.         jnz     .return0
  125. ; number of fats must be nonzero
  126.         cmp     byte [ebx+0x10], 0
  127.         jz      .return0
  128. ; The only reason to be invalid partition now is FAT12. Since the test for
  129. ; FAT size requires knowledge of some calculated values, which are also used
  130. ; in the normal operation, let's hope for the best and allocate data now; if
  131. ; it will prove wrong, just deallocate it.
  132.         movi    eax, sizeof.FAT
  133.         call    malloc
  134.         test    eax, eax
  135.         jz      .return0
  136.         mov     ecx, dword [ebp+PARTITION.FirstSector]
  137.         mov     dword [eax+FAT.FirstSector], ecx
  138.         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
  139.         mov     dword [eax+FAT.FirstSector+4], ecx
  140.         mov     ecx, dword [ebp+PARTITION.Length]
  141.         mov     dword [eax+FAT.Length], ecx
  142.         mov     ecx, dword [ebp+PARTITION.Length+4]
  143.         mov     dword [eax+FAT.Length+4], ecx
  144.         mov     ecx, [ebp+PARTITION.Disk]
  145.         mov     [eax+FAT.Disk], ecx
  146.         mov     [eax+FAT.FSUserFunctions], fat_user_functions
  147.         or      [eax+FAT.fat_in_cache], -1
  148.         mov     [eax+FAT.fat_change], 0
  149.         push    ebp
  150.         mov     ebp, eax
  151.         lea     ecx, [ebp+FAT.Lock]
  152.         call    mutex_init
  153.         movzx   eax, word [ebx+0xe]     ; sectors reserved
  154.         mov     [ebp+FAT.FAT_START], eax
  155.         movzx   eax, byte [ebx+0xd]     ; sectors per cluster
  156.         mov     [ebp+FAT.SECTORS_PER_CLUSTER], eax
  157.         movzx   ecx, word [ebx+0xb]     ; bytes per sector
  158.         mov     [ebp+FAT.BYTES_PER_SECTOR], ecx
  159.         movzx   eax, word [ebx+0x11]    ; count of rootdir entries (=0 fat32)
  160.         shl     eax, 5                  ; mul 32
  161.         dec     ecx
  162.         add     eax, ecx                ; round up if not equal count
  163.         inc     ecx                     ; bytes per sector
  164.         xor     edx, edx
  165.         div     ecx
  166.         mov     [ebp+FAT.ROOT_SECTORS], eax     ; count of rootdir sectors
  167.         movzx   eax, word [ebx+0x16]    ; sectors per fat <65536
  168.         test    eax, eax
  169.         jnz     @f
  170.         mov     eax, [ebx+0x24]         ; sectors per fat
  171. @@:
  172.         mov     [ebp+FAT.SECTORS_PER_FAT], eax
  173.         movzx   eax, byte [ebx+0x10]    ; number of fats
  174.         mov     [ebp+FAT.NUMBER_OF_FATS], eax
  175.         mul     [ebp+FAT.SECTORS_PER_FAT]
  176.         test    edx, edx
  177.         jnz     .free_return0
  178.         add     eax, [ebp+FAT.FAT_START]
  179.         jc      .free_return0
  180.         mov     [ebp+FAT.ROOT_START], eax       ; rootdir = fat_start + fat_size * fat_count
  181.         add     eax, [ebp+FAT.ROOT_SECTORS]     ; rootdir sectors should be 0 on fat32
  182.         jc      .free_return0
  183.         mov     [ebp+FAT.DATA_START], eax       ; data area = rootdir + rootdir_size
  184.         movzx   eax, word [ebx+0x13]    ; total sector count <65536
  185.         test    eax, eax
  186.         jnz     @f
  187.         mov     eax, [ebx+0x20]         ; total sector count
  188. @@:
  189.         cmp     dword [ebp+FAT.Length+4], 0
  190.         jnz     @f
  191.         cmp     eax, dword [ebp+FAT.Length]
  192.         ja      .free_return0
  193. @@:
  194.         mov     dword [ebp+FAT.Length], eax
  195.         and     dword [ebp+FAT.Length+4], 0
  196.         sub     eax, [ebp+FAT.DATA_START]       ; eax = count of data sectors
  197.         jc      .free_return0
  198.         xor     edx, edx
  199.         div     [ebp+FAT.SECTORS_PER_CLUSTER]
  200.         inc     eax
  201.         mov     [ebp+FAT.LAST_CLUSTER], eax
  202.         dec     eax                     ; cluster count
  203.         jz      .free_return0
  204.         mov     [ebp+FAT.fatStartScan], 2
  205.         cmp     eax, 0xfff5
  206.         jb      .fat16
  207. .fat32:
  208.         pusha
  209.         lea     esi, [ebx+71]
  210.         lea     edi, [ebp+FAT.volumeLabel]
  211.         movsd
  212.         movsd
  213.         movsd
  214.         popa
  215.         mov     eax, [ebx+0x2c]         ; rootdir cluster
  216.         mov     [ebp+FAT.ROOT_CLUSTER], eax
  217.         movzx   eax, word [ebx+0x30]
  218.         mov     [ebp+FAT.ADR_FSINFO], eax
  219.         push    ebx
  220.         add     ebx, 512
  221.         call    fs_read32_sys
  222.         test    eax, eax
  223.         jnz     @f
  224.         mov     eax, [ebx+0x1ec]
  225.         cmp     eax, -1
  226.         jz      @f
  227.         mov     [ebp+FAT.fatStartScan], eax
  228. @@:
  229.         pop     ebx
  230.         mov     [ebp+FAT.fatRESERVED], 0x0FFFFFF6
  231.         mov     [ebp+FAT.fatBAD], 0x0FFFFFF7
  232.         mov     [ebp+FAT.fatEND], 0x0FFFFFF8
  233.         mov     [ebp+FAT.fatMASK], 0x0FFFFFFF
  234.         mov     al, 32
  235. .fat_not_12_finalize:
  236.         mov     [ebp+FAT.fs_type], al
  237. ; For FAT16 and FAT32, allocate 512 bytes for FAT cache.
  238.         mov     eax, 512
  239.         call    malloc
  240.         test    eax, eax
  241.         jz      .free_return0
  242.         mov     [ebp+FAT.fat_cache_ptr], eax
  243.         mov     eax, ebp
  244.         pop     ebp
  245.         ret
  246.  
  247. .fat16:
  248.         pusha
  249.         lea     esi, [ebx+43]
  250.         lea     edi, [ebp+FAT.volumeLabel]
  251.         movsd
  252.         movsd
  253.         movsd
  254.         popa
  255.         cmp     eax, 0xff5
  256.         jb      .fat12
  257.         and     [ebp+FAT.ROOT_CLUSTER], 0
  258.         mov     [ebp+FAT.fatRESERVED], 0x0000FFF6
  259.         mov     [ebp+FAT.fatBAD], 0x0000FFF7
  260.         mov     [ebp+FAT.fatEND], 0x0000FFF8
  261.         mov     [ebp+FAT.fatMASK], 0x0000FFFF
  262.         mov     al, 16
  263.         jmp     .fat_not_12_finalize
  264.  
  265. .fat12:
  266.         and     [ebp+FAT.ROOT_CLUSTER], 0
  267.         mov     [ebp+FAT.fatRESERVED], 0xFF6
  268.         mov     [ebp+FAT.fatBAD], 0xFF7
  269.         mov     [ebp+FAT.fatEND], 0xFFF
  270.         mov     [ebp+FAT.fatMASK], 0xFFF
  271.         mov     al, 12
  272.         mov     [ebp+FAT.fs_type], al
  273. ; For FAT12, allocate&read data for entire table:
  274. ; calculate A = ALIGN_UP(NUM_CLUSTERS, 8),
  275. ; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data.
  276.         mov     eax, [ebp+FAT.LAST_CLUSTER]
  277.         and     eax, not 7
  278.         add     eax, 8
  279.         mov     edx, eax
  280.         lea     eax, [eax*3]
  281.         add     eax, 512*2-1
  282.         shr     eax, 10
  283.         shl     eax, 9
  284.         lea     eax, [eax+edx*2]
  285.         call    malloc
  286.         test    eax, eax
  287.         jz      .free_return0
  288. ; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes.
  289.         push    ebx
  290.         mov     [ebp+FAT.fat_cache_ptr], eax
  291.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  292.         lea     edx, [(edx+1)*3 + 512*2-1]
  293.         shr     edx, 10
  294.         xchg    eax, ebx
  295.         xor     eax, eax
  296. .read_fat:
  297.         push    eax
  298.         add     eax, [ebp+FAT.FAT_START]
  299.         call    fs_read32_sys
  300.         test    eax, eax
  301.         pop     eax
  302.         jz      @f
  303.         mov     eax, [ebp+FAT.fat_cache_ptr]
  304.         call    free
  305.         pop     ebx
  306.         jmp     .free_return0
  307.  
  308. @@:
  309.         add     ebx, 512
  310.         inc     eax
  311.         cmp     eax, edx
  312.         jb      .read_fat
  313.         mov     [ebp+FAT.fat12_unpacked_ptr], ebx
  314.         pushad
  315.         mov     esi, [ebp+FAT.fat_cache_ptr]
  316.         mov     edi, [ebp+FAT.fat12_unpacked_ptr]
  317.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  318.         and     edx, not 7
  319.         lea     edx, [edi+(edx+8)*2]
  320.         push    edx
  321. @@:
  322.         mov     eax, dword [esi]
  323.         mov     ebx, dword [esi+4]
  324.         mov     ecx, dword [esi+8]
  325.         mov     edx, ecx
  326.         shr     edx, 4
  327.         shr     dx, 4
  328.         xor     ch, ch
  329.         shld    ecx, ebx, 20
  330.         shr     cx, 4
  331.         shld    ebx, eax, 12
  332.         and     ebx, 0x0fffffff
  333.         shr     bx, 4
  334.         shl     eax, 4
  335.         and     eax, 0x0fffffff
  336.         shr     ax, 4
  337.         mov     dword [edi], eax
  338.         mov     dword [edi+4], ebx
  339.         mov     dword [edi+8], ecx
  340.         mov     dword [edi+12], edx
  341.         add     edi, 16
  342.         add     esi, 12
  343.         cmp     edi, [esp]
  344.         jnz     @b
  345.         pop     eax
  346.         popad
  347.         mov     eax, ebp
  348.         pop     ebx ebp
  349.         ret
  350.  
  351. fat_free:
  352.         push    eax
  353.         mov     eax, [eax+FAT.fat_cache_ptr]
  354.         call    free
  355.         pop     eax
  356.         jmp     free
  357.  
  358. iglobal
  359. label fat_legal_chars byte
  360. ; 0 = not allowed
  361. ; 1 = allowed only in long names
  362. ; 3 = allowed
  363.         times 32 db 0
  364. ;                 ! " # $ % & ' ( ) * + , - . /
  365.         db      1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
  366. ;               0 1 2 3 4 5 6 7 8 9 : ; < = > ?
  367.         db      3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
  368. ;               @ A B C D E F G H I J K L M N O
  369.         db      3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
  370. ;               P Q R S T U V W X Y Z [ \ ] ^ _
  371.         db      3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
  372. ;               ` a b c d e f g h i j k l m n o
  373.         db      3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
  374. ;               p q r s t u v w x y z { | } ~
  375.         db      3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
  376. endg
  377.  
  378. fat_name_is_legal:
  379. ; in: esi -> UTF-8 name
  380. ; out: CF=1 -> legal
  381.         push    esi
  382.         xor     eax, eax
  383. @@:
  384.         lodsb
  385.         test    al, al
  386.         js      @b
  387.         test    [fat_legal_chars+eax], 1
  388.         jnz     @b
  389.         test    al, al
  390.         jnz     @f
  391.         stc
  392. @@:
  393.         pop     esi
  394.         ret
  395.  
  396. fat_next_short_name:
  397. ; in: edi->8+3 name
  398. ; out: name corrected, CF=1 -> error
  399.         pushad
  400.         mov     ecx, 8
  401.         mov     al, '~'
  402.         std
  403.         push    edi
  404.         add     edi, 7
  405.         repnz scasb
  406.         pop     edi
  407.         cld
  408.         jz      .tilde
  409. ; tilde is not found, insert "~1" at end
  410.         add     edi, 6
  411.         cmp     word [edi], '  '
  412.         jnz     .insert_tilde
  413. @@:
  414.         dec     edi
  415.         cmp     byte [edi], ' '
  416.         jz      @b
  417.         inc     edi
  418. .insert_tilde:
  419.         mov     word [edi], '~1'
  420.         popad
  421.         clc
  422.         ret
  423.  
  424. .tilde:
  425.         push    edi
  426.         add     edi, 7
  427.         xor     ecx, ecx
  428. @@: ; after tilde may be only digits and trailing spaces
  429.         cmp     byte [edi], '~'
  430.         jz      .break
  431.         cmp     byte [edi], ' '
  432.         jz      .space
  433.         cmp     byte [edi], '9'
  434.         jnz     .found
  435.         dec     edi
  436.         jmp     @b
  437.  
  438. .space:
  439.         dec     edi
  440.         inc     ecx
  441.         jmp     @b
  442.  
  443. .found:
  444.         inc     byte [edi]
  445.         add     dword [esp], 8
  446.         jmp     .zerorest
  447.  
  448. .break:
  449.         jecxz   .noplace
  450.         inc     edi
  451.         mov     al, '1'
  452. @@:
  453.         xchg    al, [edi]
  454.         inc     edi
  455.         cmp     al, ' '
  456.         mov     al, '0'
  457.         jnz     @b
  458. .succ:
  459.         pop     edi
  460.         popad
  461.         clc
  462.         ret
  463.  
  464. .noplace:
  465.         dec     edi
  466.         cmp     edi, [esp]
  467.         jz      .err
  468.         add     dword [esp], 8
  469.         mov     word [edi], '~1'
  470.         inc     edi
  471.         inc     edi
  472. @@:
  473.         mov     byte [edi], '0'
  474. .zerorest:
  475.         inc     edi
  476.         cmp     edi, [esp]
  477.         jb      @b
  478.         pop     edi
  479.         popad
  480.         ret
  481.  
  482. .err:
  483.         pop     edi
  484.         popad
  485.         stc
  486.         ret
  487.  
  488. fat_gen_short_name:
  489. ;   in:
  490. ; esi -> UTF-8 name
  491. ; edi -> buffer (8+3=11 chars)
  492.         pushad
  493.         mov     eax, '    '
  494.         push    edi
  495.         stosd
  496.         stosd
  497.         stosd
  498.         pop     edi
  499.         xor     eax, eax
  500.         movi    ebx, 8
  501.         lea     ecx, [edi+8]
  502. .loop:
  503.         lodsb
  504.         test    al, al
  505.         js      .space
  506.         jz      .done
  507.         test    [fat_legal_chars+eax], 2
  508.         jz      .space
  509.         cmp     al, '.'
  510.         jz      .dot
  511.         dec     bl
  512.         jns     .store
  513.         inc     bl
  514. .space:
  515.         or      bh, 1
  516.         jmp     .loop
  517.  
  518. .store:
  519.         call    cp866toUpper
  520.         stosb
  521.         jmp     .loop
  522.  
  523. .dot:
  524.         test    bh, 2
  525.         jz      .firstdot
  526.         pop     ebx
  527.         add     ebx, edi
  528.         sub     ebx, ecx
  529.         push    ebx
  530.         cmp     ebx, ecx
  531.         jb      @f
  532.         pop     ebx
  533.         push    ecx
  534. @@:
  535.         cmp     edi, ecx
  536.         jbe     .skip
  537. @@:
  538.         dec     edi
  539.         mov     al, [edi]
  540.         dec     ebx
  541.         mov     [ebx], al
  542.         mov     byte [edi], ' '
  543.         cmp     edi, ecx
  544.         ja      @b
  545. .skip:
  546.         mov     bh, 3
  547.         jmp     @f
  548.  
  549. .firstdot:
  550.         cmp     bl, 8
  551.         jz      .space
  552.         push    edi
  553.         or      bh, 2
  554. @@:
  555.         mov     edi, ecx
  556.         mov     bl, 3
  557.         jmp     .loop
  558.  
  559. .done:
  560.         test    bh, 2
  561.         jz      @f
  562.         pop     edi
  563. @@:
  564.         lea     edi, [ecx-8]
  565.         test    bh, 1
  566.         jz      @f
  567.         call    fat_next_short_name
  568. @@:
  569.         popad
  570.         ret
  571.  
  572. set_FAT:
  573. ; in: eax = cluster, edx = value to save
  574. ; out: edx = old value, CF=1 -> error
  575.         push    eax ebx esi
  576.         cmp     eax, 2
  577.         jc      .ret
  578.         cmp     [ebp+FAT.LAST_CLUSTER], eax
  579.         jc      .ret
  580.         cmp     [ebp+FAT.fs_type], 12
  581.         je      .FAT12
  582.         cmp     [ebp+FAT.fs_type], 16
  583.         je      @f
  584.         add     eax, eax
  585. @@:
  586.         add     eax, eax
  587.         mov     esi, 511
  588.         and     esi, eax
  589.         shr     eax, 9
  590.         add     eax, [ebp+FAT.FAT_START]
  591.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  592.         cmp     eax, [ebp+FAT.fat_in_cache]
  593.         je      .inCache
  594.         cmp     [ebp+FAT.fat_change], 0
  595.         je      @f
  596.         call    write_fat_sector
  597. @@:
  598.         mov     [ebp+FAT.fat_in_cache], eax
  599.         call    fs_read32_sys
  600.         test    eax, eax
  601.         jne     .error
  602. .inCache:
  603.         cmp     [ebp+FAT.fs_type], 16
  604.         jne     .test32
  605.         xchg    [ebx+esi], dx   ; save new value and get old value
  606.         jmp     .write
  607.  
  608. .test32:
  609.         mov     eax, [ebp+FAT.fatMASK]
  610.         and     edx, eax
  611.         xor     eax, -1         ; mask for high bits
  612.         and     eax, [ebx+esi]  ; get high 4 bits
  613.         or      eax, edx
  614.         mov     edx, [ebx+esi]  ; get old value
  615.         mov     [ebx+esi], eax  ; save new value
  616. .write:
  617.         mov     [ebp+FAT.fat_change], 1
  618.         and     edx, [ebp+FAT.fatMASK]
  619. .ret:
  620.         pop     esi ebx eax
  621.         ret
  622.  
  623. .error:
  624.         stc
  625.         jmp     .ret
  626.  
  627. .FAT12:
  628.         test    edx, 0xF000
  629.         jnz     .error
  630.         mov     ebx, [ebp+FAT.fat12_unpacked_ptr]
  631.         xchg    [ebx+eax*2], dx
  632.         mov     [ebp+FAT.fat_change], 1
  633.         jmp     .ret
  634.  
  635. get_FAT:
  636. ; in: eax = cluster
  637. ; out: eax = next cluster, CF=1 -> error
  638.         push    ebx esi
  639.         cmp     [ebp+FAT.fs_type], 12
  640.         je      .FAT12
  641.         cmp     [ebp+FAT.fs_type], 16
  642.         je      @f
  643.         add     eax, eax
  644. @@:
  645.         add     eax, eax
  646.         mov     esi, 511
  647.         and     esi, eax
  648.         shr     eax, 9
  649.         add     eax, [ebp+FAT.FAT_START]
  650.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  651.         cmp     eax, [ebp+FAT.fat_in_cache]
  652.         je      .inCache
  653.         cmp     [ebp+FAT.fat_change], 0
  654.         je      @f
  655.         call    write_fat_sector
  656. @@:
  657.         mov     [ebp+FAT.fat_in_cache], eax
  658.         call    fs_read32_sys
  659.         test    eax, eax
  660.         jnz     .error
  661. .inCache:
  662.         mov     eax, [ebx+esi]
  663.         and     eax, [ebp+FAT.fatMASK]
  664. .ret:
  665.         pop     esi ebx
  666.         ret
  667.  
  668. .error:
  669.         stc
  670.         jmp     .ret
  671.  
  672. .FAT12:
  673.         mov     ebx, [ebp+FAT.fat12_unpacked_ptr]
  674.         movzx   eax, word [ebx+eax*2]
  675.         jmp     .ret
  676.  
  677. get_free_FAT:
  678. ; out: eax = number of first free cluster, CF=1 -> disk full
  679.         push    ecx
  680.         mov     ecx, [ebp+FAT.LAST_CLUSTER]
  681.         mov     eax, [ebp+FAT.fatStartScan]
  682.         cmp     [ebp+FAT.fs_type], 12
  683.         jz      get_free_FAT12
  684.         dec     ecx
  685.         cmp     eax, 2
  686.         jb      .reset
  687. .test:
  688.         cmp     eax, [ebp+FAT.LAST_CLUSTER]
  689.         jbe     .inRange
  690. .reset:
  691.         mov     eax, 2
  692. .inRange:
  693.         push    eax
  694.         call    get_FAT
  695.         jc      @f
  696.         test    eax, eax
  697.         pop     eax
  698.         je      .found
  699.         inc     eax
  700.         dec     ecx
  701.         jnz     .test
  702. .notFound:
  703.         pop     ecx
  704.         stc
  705.         ret
  706.  
  707. @@:
  708.         pop     eax
  709.         jmp     .notFound
  710.  
  711. .found:
  712.         lea     ecx, [eax+1]
  713.         mov     [ebp+FAT.fatStartScan], ecx
  714.         pop     ecx
  715.         clc
  716.         ret
  717.  
  718. get_free_FAT12:
  719.         push    edx edi
  720.         mov     edi, [ebp+FAT.fat12_unpacked_ptr]
  721.         cmp     eax, 2
  722.         jb      .reset
  723.         cmp     eax, ecx
  724.         jbe     @f
  725. .reset:
  726.         mov     eax, 2
  727. @@:
  728.         mov     edx, eax
  729.         lea     edi, [edi+eax*2]
  730.         sub     ecx, eax
  731.         inc     ecx
  732.         xor     eax, eax
  733.         repnz scasw
  734.         jz      .found
  735.         cmp     edx, 2
  736.         jz      .notfound
  737.         mov     edi, [ebp+FAT.fat12_unpacked_ptr]
  738.         lea     ecx, [edx-2]
  739.         repnz scasw
  740.         jnz     .notfound
  741. .found:
  742.         sub     edi, [ebp+FAT.fat12_unpacked_ptr]
  743.         shr     edi, 1
  744.         mov     [ebp+FAT.fatStartScan], edi
  745.         lea     eax, [edi-1]
  746. @@:
  747.         pop     edi edx ecx
  748.         ret
  749.  
  750. .notfound:
  751.         stc
  752.         jmp     @b
  753.  
  754. write_fat_sector:
  755.         push    eax ebx ecx
  756.         mov     [ebp+FAT.fat_change], 0
  757.         mov     eax, [ebp+FAT.fat_in_cache]
  758.         cmp     eax, -1
  759.         jz      @f
  760.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  761.         mov     ecx, [ebp+FAT.NUMBER_OF_FATS]
  762. .write_next_fat:
  763.         push    eax
  764.         call    fs_write32_sys
  765.         pop     eax
  766.         add     eax, [ebp+FAT.SECTORS_PER_FAT]
  767.         dec     ecx
  768.         jnz     .write_next_fat
  769. @@:
  770.         pop     ecx ebx eax
  771.         ret
  772.  
  773. get_date_for_file:
  774. ;   out in ax:
  775. ; bits 0-4 = day
  776. ; bits 5-8 = month
  777. ; bits 9-15 = count of years from 1980
  778.         mov     al, 7
  779.         call    fsReadCMOS
  780.         ror     eax, 5
  781.         mov     al, 8
  782.         call    fsReadCMOS
  783.         ror     eax, 4
  784.         mov     al, 9
  785.         call    fsReadCMOS
  786.         add     ax, 20
  787.         rol     eax, 9
  788.         ret
  789.  
  790. get_time_for_file:
  791. ;   out in ax:
  792. ; bits 0-4 = second (the low bit is lost)
  793. ; bits 5-10 = minute
  794. ; bits 11-15 = hour
  795.         mov     al, 0
  796.         call    fsReadCMOS
  797.         ror     eax, 6
  798.         mov     al, 2
  799.         call    fsReadCMOS
  800.         ror     eax, 6
  801.         mov     al, 4
  802.         call    fsReadCMOS
  803.         rol     eax, 11
  804.         ret
  805.  
  806. add_disk_free_space:
  807. ; in: ecx = cluster count (signed)
  808.         test    ecx, ecx
  809.         je      .ret
  810.         cmp     [ebp+FAT.fs_type], 32
  811.         jne     .ret
  812.         push    eax ebx
  813.         mov     eax, [ebp+FAT.ADR_FSINFO]
  814.         lea     ebx, [ebp+FAT.fsinfo_buffer]
  815.         call    fs_read32_sys
  816.         test    eax, eax
  817.         jnz     @f
  818.         cmp     dword [ebx+0x1fc], 0xaa550000   ; check sector id
  819.         jne     @f
  820.         add     [ebx+0x1e8], ecx
  821.         push    [ebp+FAT.fatStartScan]
  822.         pop     dword [ebx+0x1ec]
  823.         mov     eax, [ebp+FAT.ADR_FSINFO]
  824.         call    fs_write32_sys
  825. @@:
  826.         pop     ebx eax
  827. .ret:
  828.         ret
  829.  
  830. clear_cluster_chain:
  831. ; in: eax = first cluster
  832.         push    eax ecx edx
  833.         xor     ecx, ecx        ; cluster count
  834. @@:
  835.         cmp     eax, [ebp+FAT.LAST_CLUSTER]
  836.         ja      @f
  837.         cmp     eax, 2
  838.         jb      @f
  839.         cmp     eax, [ebp+FAT.ROOT_CLUSTER]
  840.         jz      @f
  841.         xor     edx, edx
  842.         call    set_FAT
  843.         jc      .ret
  844.         inc     ecx
  845.         mov     eax, edx
  846.         jmp     @b
  847.  
  848. @@:
  849.         call    add_disk_free_space
  850.         clc
  851. .ret:
  852.         pop     edx ecx eax
  853.         ret
  854.  
  855. update_disk:
  856.         cmp     [ebp+FAT.fat_change], 0
  857.         jz      .noChange
  858.         cmp     [ebp+FAT.fs_type], 12
  859.         jz      .fat12
  860.         call    write_fat_sector
  861. .noChange:
  862.         mov     esi, [ebp+PARTITION.Disk]
  863.         call    disk_sync
  864.         ret
  865.  
  866. .fat12:
  867.         mov     esi, [ebp+FAT.fat12_unpacked_ptr]
  868.         mov     edi, [ebp+FAT.fat_cache_ptr]
  869.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  870.         and     edx, not 7
  871.         lea     edx, [esi+(edx+8)*2]
  872. @@:
  873.         mov     eax, dword [esi]
  874.         mov     ebx, dword [esi+4]
  875.         shl     ax, 4
  876.         shl     eax, 4
  877.         shl     bx, 4
  878.         shr     ebx, 4
  879.         shrd    eax, ebx, 8
  880.         shr     ebx, 8
  881.         mov     dword [edi], eax
  882.         mov     word [edi+4], bx
  883.         add     edi, 6
  884.         add     esi, 8
  885.         cmp     esi, edx
  886.         jb      @b
  887.         mov     esi, [ebp+FAT.NUMBER_OF_FATS]
  888.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  889.         lea     edx, [(edx+1)*3 + 512*2-1]
  890.         shr     edx, 10
  891.         push    [ebp+FAT.FAT_START]
  892. .write_fats:
  893.         xor     eax, eax
  894.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  895. .loop1:
  896.         push    eax
  897.         add     eax, [esp+4]
  898.         call    fs_write32_sys
  899.         test    eax, eax
  900.         pop     eax
  901.         jnz     @f
  902.         add     ebx, 512
  903.         inc     eax
  904.         cmp     eax, edx
  905.         jb      .loop1
  906.         pop     eax
  907.         add     eax, [ebp+FAT.SECTORS_PER_FAT]
  908.         push    eax
  909.         dec     esi
  910.         jnz     .write_fats
  911. @@:
  912.         pop     eax
  913.         mov     [ebp+FAT.fat_change], 0
  914.         jmp     .noChange
  915.  
  916. fat_lock:
  917.         lea     ecx, [ebp+FAT.Lock]
  918.         jmp     mutex_lock
  919.  
  920. fat_unlock:
  921.         lea     ecx, [ebp+FAT.Lock]
  922.         jmp     mutex_unlock
  923.  
  924. fat_get_name:
  925. ; in: edi -> FAT entry, esi -> buffer for UTF-16 name
  926. ; out: CF=1 -> no valid entry
  927.         cmp     byte [edi], 0
  928.         jz      .no
  929.         cmp     byte [edi], 0xE5
  930.         jz      .no
  931.         cmp     byte [edi+11], 0xF
  932.         jz      .longname
  933.         push    edi
  934.         xchg    esi, edi
  935.         test    byte [esi+11], 8
  936.         jnz     .label
  937.         pushd   ecx 8
  938.         pop     ecx
  939. @@:
  940.         lodsb
  941.         call    ansi2uni_char
  942.         stosw
  943.         loop    @b
  944.         mov     cl, 8
  945. @@:
  946.         cmp     word [edi-2], ' '
  947.         jnz     @f
  948.         sub     edi, 2
  949.         loop    @b
  950. @@:
  951.         mov     word [edi], '.'
  952.         add     edi, 2
  953.         mov     cl, 3
  954. @@:
  955.         lodsb
  956.         call    ansi2uni_char
  957.         stosw
  958.         loop    @b
  959.         mov     cl, 3
  960. @@:
  961.         cmp     word [edi-2], ' '
  962.         jnz     @f
  963.         sub     edi, 2
  964.         loop    @b
  965.         sub     edi, 2
  966. @@:
  967.         and     word [edi], 0   ; CF=0
  968.         pop     ecx edi
  969.         ret
  970.  
  971. .label:
  972.         lea     edi, [ebp+FAT.volumeLabel]
  973.         movsd
  974.         movsd
  975.         movsd
  976.         pop     edi
  977. .no:
  978.         stc
  979.         ret
  980.  
  981. .longname:
  982.         mov     al, byte [edi]
  983.         and     eax, 0x3F
  984.         dec     eax
  985.         cmp     al, 20
  986.         jae     .no     ; ignore invalid entries
  987.         mov     word [esi+260*2], 0     ; force null-terminating for orphans
  988.         imul    eax, 13*2
  989.         test    byte [edi], 0x40
  990.         jz      @f
  991.         mov     word [esi+eax+13*2], 0
  992. @@: ; copy name (13 chars in UTF-16)
  993.         push    edi
  994.         inc     edi
  995.         add     esi, eax
  996.         xchg    esi, edi
  997.         movsd
  998.         movsd
  999.         movsw
  1000.         add     esi, 3
  1001.         movsd
  1002.         movsd
  1003.         movsd
  1004.         add     esi, 2
  1005.         movsd
  1006.         pop     edi
  1007.         test    eax, eax
  1008.         jnz     .no ; if this is not first entry, more processing required
  1009.         ret
  1010.  
  1011. fat_find_lfn:
  1012. ;   in:
  1013. ; esi -> path in UTF-8
  1014. ; parameters in the stack
  1015. ;   out:
  1016. ; esi -> next name in the path
  1017. ; edi -> direntry
  1018. ; CF=1 -> file not found, eax = error code
  1019.         lea     eax, [esp+12]
  1020.         call    dword [eax-4]
  1021.         jc      .reterr
  1022.         sub     esp, 262*2      ; reserve place for LFN
  1023. .l1:
  1024.         push    esi
  1025.         lea     esi, [esp+4]
  1026.         call    fat_get_name
  1027.         pop     esi
  1028.         jc      .no
  1029.         push    edi esi
  1030.         lea     edi, [esp+8]
  1031. @@:
  1032.         call    utf8to16
  1033.         call    utf16toUpper
  1034.         mov     edx, eax
  1035.         mov     ax, [edi]
  1036.         call    utf16toUpper
  1037.         cmp     ax, dx
  1038.         jnz     .done
  1039.         add     edi, 2
  1040.         test    ax, ax
  1041.         jnz     @b
  1042.         dec     esi
  1043.         pop     eax edi
  1044. .found:
  1045.         add     esp, 262*2
  1046. ; if this is LFN entry, advance to true entry
  1047.         cmp     byte [edi+11], 0xF
  1048.         jnz     @f
  1049.         lea     eax, [esp+12]
  1050.         call    dword[eax-8]
  1051.         jc      .reterr
  1052. @@:
  1053.         xor     eax, eax
  1054.         ret
  1055.  
  1056. .done:
  1057.         cmp     dx, '/'
  1058.         jnz     @f
  1059.         test    ax, ax
  1060.         jnz     @f
  1061.         mov     [esp], esi
  1062. @@:
  1063.         pop     esi edi
  1064.         jz      .found
  1065. .no:
  1066.         lea     eax, [esp+262*2+12]
  1067.         call    dword[eax-8]
  1068.         jnc     .l1
  1069.         add     esp, 262*2
  1070. .reterr:
  1071.         stc
  1072.         ret
  1073.  
  1074. fat_time_to_bdfe:
  1075. ; in: eax=FAT time
  1076. ; out: eax=BDFE time
  1077.         push    ecx edx
  1078.         mov     ecx, eax
  1079.         mov     edx, eax
  1080.         shr     eax, 11
  1081.         shl     eax, 16 ; hours
  1082.         and     edx, 0x1F
  1083.         add     edx, edx
  1084.         mov     al, dl  ; seconds
  1085.         shr     ecx, 5
  1086.         and     ecx, 0x3F
  1087.         mov     ah, cl  ; minutes
  1088.         pop     edx ecx
  1089.         ret
  1090.  
  1091. fat_date_to_bdfe:
  1092.         push    ecx edx
  1093.         mov     ecx, eax
  1094.         mov     edx, eax
  1095.         shr     eax, 9
  1096.         add     ax, 1980
  1097.         shl     eax, 16 ; year
  1098.         and     edx, 0x1F
  1099.         mov     al, dl  ; day
  1100.         shr     ecx, 5
  1101.         and     ecx, 0xF
  1102.         mov     ah, cl  ; month
  1103.         pop     edx ecx
  1104.         ret
  1105.  
  1106. bdfe_to_fat_time:
  1107.         push    edx
  1108.         mov     edx, eax
  1109.         shr     eax, 16
  1110.         and     dh, 0x3F
  1111.         shl     eax, 6
  1112.         or      al, dh
  1113.         shr     dl, 1
  1114.         and     dl, 0x1F
  1115.         shl     eax, 5
  1116.         or      al, dl
  1117.         pop     edx
  1118.         ret
  1119.  
  1120. bdfe_to_fat_date:
  1121.         push    edx
  1122.         mov     edx, eax
  1123.         shr     eax, 16
  1124.         sub     ax, 1980
  1125.         and     dh, 0xF
  1126.         shl     eax, 4
  1127.         or      al, dh
  1128.         and     dl, 0x1F
  1129.         shl     eax, 5
  1130.         or      al, dl
  1131.         pop     edx
  1132.         ret
  1133.  
  1134. fat_entry_to_bdfe:
  1135. ; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
  1136.         mov     eax, [ebp-4]
  1137.         mov     [esi+4], eax    ; cp866/UNICODE name
  1138. fat_entry_to_bdfe2:
  1139.         movzx   eax, byte [edi+11]
  1140.         mov     [esi], eax      ; attributes
  1141.         movzx   eax, word [edi+14]
  1142.         call    fat_time_to_bdfe
  1143.         mov     [esi+8], eax    ; creation time
  1144.         movzx   eax, word [edi+16]
  1145.         call    fat_date_to_bdfe
  1146.         mov     [esi+12], eax   ; creation date
  1147.         and     dword [esi+16], 0       ; last access time is not supported on FAT
  1148.         movzx   eax, word [edi+18]
  1149.         call    fat_date_to_bdfe
  1150.         mov     [esi+20], eax   ; last access date
  1151.         movzx   eax, word [edi+22]
  1152.         call    fat_time_to_bdfe
  1153.         mov     [esi+24], eax   ; last write time
  1154.         movzx   eax, word [edi+24]
  1155.         call    fat_date_to_bdfe
  1156.         mov     [esi+28], eax   ; last write date
  1157.         mov     eax, [edi+28]
  1158.         mov     [esi+32], eax   ; file size (low dword)
  1159.         xor     eax, eax
  1160.         mov     [esi+36], eax   ; file size (high dword)
  1161.         test    ebp, ebp
  1162.         jz      .ret
  1163.         add     esi, 40
  1164.         push    edi esi
  1165.         mov     edi, esi
  1166.         mov     esi, ebp
  1167.         cmp     byte [ebp-4], 2
  1168.         jz      .utf16
  1169.         cmp     byte [ebp-4], 3
  1170.         jz      .utf8
  1171. @@:
  1172.         lodsw
  1173.         call    uni2ansi_char
  1174.         stosb
  1175.         test    al, al
  1176.         jnz     @b
  1177.         pop     esi edi
  1178.         add     esi, 264
  1179. .ret:
  1180.         ret
  1181.  
  1182. .utf8:
  1183.         push    ecx
  1184.         mov     ecx, 519
  1185.         call    UTF16to8_string
  1186.         pop     ecx
  1187.         jmp     @f
  1188.  
  1189. .utf16:
  1190.         lodsw
  1191.         stosw
  1192.         test    eax, eax
  1193.         jnz     .utf16
  1194. @@:
  1195.         pop     esi edi
  1196.         add     esi, 520
  1197.         ret
  1198.  
  1199. bdfe_to_fat_entry:
  1200. ; convert BDFE at edx to FAT entry at edi
  1201. ; destroys eax
  1202. ; attributes byte
  1203.         test    byte [edi+11], 8        ; volume label?
  1204.         jnz     @f
  1205.         mov     al, [edx]
  1206.         and     al, 0x27
  1207.         and     byte [edi+11], 0x10
  1208.         or      byte [edi+11], al
  1209. @@:
  1210.         mov     eax, [edx+8]
  1211.         call    bdfe_to_fat_time
  1212.         mov     [edi+14], ax            ; creation time
  1213.         mov     eax, [edx+12]
  1214.         call    bdfe_to_fat_date
  1215.         mov     [edi+16], ax            ; creation date
  1216.         mov     eax, [edx+20]
  1217.         call    bdfe_to_fat_date
  1218.         mov     [edi+18], ax            ; last access date
  1219.         mov     eax, [edx+24]
  1220.         call    bdfe_to_fat_time
  1221.         mov     [edi+22], ax            ; last write time
  1222.         mov     eax, [edx+28]
  1223.         call    bdfe_to_fat_date
  1224.         mov     [edi+24], ax            ; last write date
  1225.         ret
  1226.  
  1227. hd_find_lfn:
  1228. ; in: esi -> path string in UTF-8
  1229. ; out: CF=1 - file not found, eax=error code
  1230. ;      else CF=0 and edi->direntry, eax=sector
  1231.         push    esi edi
  1232.         push    0
  1233.         push    0
  1234.         push    fat1x_root_first
  1235.         push    fat1x_root_next
  1236.         mov     eax, [ebp+FAT.ROOT_CLUSTER]
  1237.         cmp     [ebp+FAT.fs_type], 32
  1238.         jz      .fat32
  1239. .loop:
  1240.         and     [ebp+FAT.longname_sec1], 0
  1241.         and     [ebp+FAT.longname_sec2], 0
  1242.         call    fat_find_lfn
  1243.         jc      .notfound
  1244.         cmp     byte [esi], 0
  1245.         jz      .found
  1246.         test    byte [edi+11], 10h
  1247.         jz      .notfound
  1248.         and     dword [esp+12], 0
  1249.         mov     eax, [edi+20-2]
  1250.         mov     ax, [edi+26]    ; cluster
  1251. .fat32:
  1252.         mov     [esp+8], eax
  1253.         mov     dword [esp+4], fat_notroot_first
  1254.         mov     dword [esp], fat_notroot_next
  1255.         jmp     .loop
  1256.  
  1257. .notfound:
  1258.         add     esp, 16
  1259.         pop     edi esi
  1260.         stc
  1261.         ret
  1262.  
  1263. .found:
  1264.         lea     eax, [esp+8]
  1265.         cmp     dword [eax], 0
  1266.         jz      .root
  1267.         call    fat_get_sector
  1268.         jmp     .cmn
  1269.  
  1270. .root:
  1271.         mov     eax, [eax+4]
  1272.         add     eax, [ebp+FAT.ROOT_START]
  1273. .cmn:
  1274.         add     esp, 20         ; CF=0
  1275.         pop     esi
  1276.         ret
  1277.  
  1278. ;----------------------------------------------------------------
  1279. fat_Read:
  1280.         call    fat_lock
  1281.         call    hd_find_lfn
  1282.         jc      .notFound
  1283.         test    byte [edi+11], 0x10     ; do not allow read directories
  1284.         jnz     .noaccess
  1285.         cmp     dword [ebx+8], 0
  1286.         jnz     .endOfFile
  1287.         mov     edx, [ebx+4]    ; file offset
  1288.         mov     ecx, [ebx+12]   ; size
  1289.         mov     ebx, [ebx+16]   ; buffer
  1290.         push    ebx
  1291.         push    0
  1292.         test    ecx, ecx
  1293.         jz      .done
  1294.         mov     eax, [edi+28]
  1295.         sub     eax, edx
  1296.         jb      .fileEnd
  1297.         cmp     eax, ecx
  1298.         jae     @f
  1299.         mov     ecx, eax
  1300.         mov     byte [esp], 6
  1301. @@:
  1302.         mov     eax, [edi+20-2]
  1303.         mov     ax, [edi+26]
  1304. ; now eax=cluster, ebx=buffer for data, ecx=count, edx=position
  1305.         mov     edi, [ebp+FAT.SECTORS_PER_CLUSTER]
  1306.         shl     edi, 9
  1307. @@:
  1308.         cmp     eax, 2
  1309.         jb      .fileEnd
  1310.         cmp     eax, [ebp+FAT.fatRESERVED]
  1311.         jae     .fileEnd
  1312.         sub     edx, edi
  1313.         jc      @f
  1314.         call    get_FAT
  1315.         jc      .noaccess2
  1316.         jmp     @b
  1317.  
  1318. .notFound:
  1319.         push    eax
  1320.         jmp     .ret
  1321.  
  1322. .noaccess:
  1323.         push    ERROR_ACCESS_DENIED
  1324.         jmp     .ret
  1325.  
  1326. .endOfFile:
  1327.         push    ERROR_END_OF_FILE
  1328. .ret:
  1329.         call    fat_unlock
  1330.         pop     eax
  1331.         xor     ebx, ebx
  1332.         ret
  1333.  
  1334. @@:
  1335.         mov     esi, eax
  1336.         dec     eax
  1337.         dec     eax
  1338.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1339.         add     eax, [ebp+FAT.DATA_START]
  1340.         add     edx, edi
  1341.         jz      .alignedCluster
  1342.         mov     edi, edx
  1343.         shr     edi, 9
  1344.         add     eax, edi
  1345.         and     edx, 511
  1346.         cmp     ecx, 512
  1347.         jc      .sectorPiece
  1348.         test    edx, edx
  1349.         jz      .alignedSector
  1350. .sectorPiece:
  1351.         push    eax ebx
  1352.         lea     ebx, [ebp+FAT.buffer]
  1353.         call    fs_read32_app
  1354.         test    eax, eax
  1355.         mov     eax, ebx
  1356.         pop     ebx
  1357.         jne     .noaccess3
  1358.         add     eax, edx
  1359.         push    ecx
  1360.         add     ecx, edx
  1361.         cmp     ecx, 512
  1362.         jbe     @f
  1363.         mov     ecx, 512
  1364. @@:
  1365.         sub     ecx, edx
  1366.         call    memmove
  1367.         sub     [esp], ecx
  1368.         add     ebx, ecx
  1369.         pop     ecx eax
  1370.         xor     edx, edx
  1371.         inc     edi
  1372.         inc     eax
  1373.         test    ecx, ecx
  1374.         jz      .done
  1375. .alignedSector:
  1376.         shl     edi, 9
  1377.         add     ecx, edi
  1378.         mov     edi, [ebp+FAT.SECTORS_PER_CLUSTER]
  1379.         shl     edi, 9
  1380. .alignedCluster:
  1381.         cmp     ecx, 512
  1382.         jc      .sectorPiece
  1383.         mov     edx, eax
  1384.         mov     eax, esi
  1385. @@:
  1386.         sub     ecx, edi
  1387.         jbe     .readEnd
  1388.         call    get_FAT
  1389.         jc      .noaccess4
  1390.         cmp     eax, 2
  1391.         jb      .fileEnd2
  1392.         cmp     eax, [ebp+FAT.fatRESERVED]
  1393.         jae     .fileEnd2
  1394.         inc     esi
  1395.         cmp     eax, esi
  1396.         jz      @b
  1397. .fragmentEnd:
  1398.         xchg    eax, esi
  1399.         dec     eax
  1400.         dec     eax
  1401.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1402.         add     eax, [ebp+FAT.DATA_START]
  1403.         push    ecx
  1404.         mov     ecx, eax
  1405.         mov     eax, esi
  1406.         dec     eax
  1407.         dec     eax
  1408.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1409.         add     eax, [ebp+FAT.DATA_START]
  1410.         push    eax
  1411. .readFragment:
  1412.         sub     ecx, edx
  1413.         mov     eax, edx
  1414.         xor     edx, edx
  1415.         call    fs_read64_app
  1416.         shl     ecx, 9
  1417.         add     ebx, ecx
  1418.         test    eax, eax
  1419.         pop     eax
  1420.         jnz     .noaccess3
  1421.         pop     ecx
  1422.         xor     edx, edx
  1423.         jecxz   .done
  1424.         jmp     .alignedCluster
  1425.  
  1426. .readEnd:
  1427.         add     ecx, edi
  1428.         mov     edi, ecx
  1429.         and     ecx, 511
  1430.         shr     edi, 9
  1431.         dec     eax
  1432.         dec     eax
  1433.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1434.         add     eax, [ebp+FAT.DATA_START]
  1435.         add     eax, edi
  1436.         push    ecx
  1437.         push    eax
  1438.         mov     ecx, eax
  1439.         jmp     .readFragment
  1440.  
  1441. .noaccess3:
  1442.         pop     eax
  1443. .noaccess2:
  1444.         mov     byte [esp], ERROR_DEVICE
  1445. .done:
  1446.         call    fat_unlock
  1447.         pop     eax edx
  1448.         sub     ebx, edx
  1449.         ret
  1450.  
  1451. .fileEnd:
  1452.         mov     byte [esp], ERROR_END_OF_FILE
  1453.         jmp     .done
  1454.  
  1455. .noaccess4:
  1456.         mov     byte [esp], ERROR_DEVICE
  1457.         jmp     @f
  1458.  
  1459. .fileEnd2:
  1460.         mov     byte [esp], ERROR_END_OF_FILE
  1461. @@:
  1462.         inc     esi
  1463.         xor     ecx, ecx
  1464.         jmp     .fragmentEnd
  1465.  
  1466. ;----------------------------------------------------------------
  1467. fat_ReadFolder:
  1468.         call    fat_lock
  1469.         mov     eax, [ebp+FAT.ROOT_CLUSTER]
  1470.         cmp     byte [esi], 0
  1471.         jz      .doit
  1472.         call    hd_find_lfn
  1473.         jc      .error
  1474.         test    byte [edi+11], 0x10     ; do not allow read files
  1475.         jz      .accessDenied
  1476.         mov     eax, [edi+20-2]
  1477.         mov     ax, [edi+26]    ; eax=cluster
  1478. .doit:
  1479.         sub     esp, 262*2      ; reserve space for LFN
  1480.         push    dword [ebx+8]   ; cp866/UNICODE name
  1481.         mov     edx, [ebx+16]   ; pointer to buffer
  1482. ; init header
  1483.         push    eax
  1484.         mov     edi, edx
  1485.         mov     ecx, 32/4
  1486.         xor     eax, eax
  1487.         rep stosd
  1488.         pop     eax
  1489.         mov     byte [edx], 1   ; version
  1490.         mov     esi, edi        ; esi points to BDFE
  1491.         mov     ecx, [ebx+12]   ; number of blocks to read
  1492.         mov     ebx, [ebx+4]    ; index of the first block
  1493. .new_cluster:
  1494.         mov     [ebp+FAT.cluster_tmp], eax
  1495.         test    eax, eax
  1496.         jnz     @f
  1497.         cmp     [ebp+FAT.fs_type], 32
  1498.         jz      .notfound
  1499.         mov     eax, [ebp+FAT.ROOT_START]
  1500.         push    [ebp+FAT.ROOT_SECTORS]
  1501.         push    ebx
  1502.         jmp     .new_sector
  1503.  
  1504. @@:
  1505.         dec     eax
  1506.         dec     eax
  1507.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1508.         push    [ebp+FAT.SECTORS_PER_CLUSTER]
  1509.         add     eax, [ebp+FAT.DATA_START]
  1510.         push    ebx
  1511. .new_sector:
  1512.         lea     ebx, [ebp+FAT.buffer]
  1513.         mov     edi, ebx
  1514.         push    eax
  1515.         call    fs_read32_sys
  1516.         test    eax, eax
  1517.         pop     eax
  1518.         jnz     .notfound2
  1519.         add     ebx, 512
  1520.         push    eax
  1521. .l1:
  1522.         push    esi
  1523.         lea     esi, [esp+20]
  1524.         call    fat_get_name
  1525.         pop     esi
  1526.         jc      .l2
  1527.         cmp     byte [edi+11], 0xF
  1528.         jnz     .do_bdfe
  1529.         add     edi, 0x20
  1530.         cmp     edi, ebx
  1531.         jb      .do_bdfe
  1532.         pop     eax
  1533.         inc     eax
  1534.         dec     dword [esp+4]
  1535.         jnz     @f
  1536.         mov     eax, [ebp+FAT.cluster_tmp]
  1537.         test    eax, eax
  1538.         jz      .done
  1539.         call    get_FAT
  1540.         jc      .notfound2
  1541.         cmp     eax, 2
  1542.         jb      .done
  1543.         cmp     eax, [ebp+FAT.fatRESERVED]
  1544.         jae     .done
  1545.         push    eax
  1546.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1547.         mov     [esp+8], eax
  1548.         pop     eax
  1549.         mov     [ebp+FAT.cluster_tmp], eax
  1550.         dec     eax
  1551.         dec     eax
  1552.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1553.         add     eax, [ebp+FAT.DATA_START]
  1554. @@:
  1555.         lea     ebx, [ebp+FAT.buffer]
  1556.         mov     edi, ebx
  1557.         push    eax
  1558.         call    fs_read32_sys
  1559.         test    eax, eax
  1560.         pop     eax
  1561.         jnz     .notfound2
  1562.         add     ebx, 512
  1563.         push    eax
  1564. .do_bdfe:
  1565.         inc     dword [edx+8]   ; new file found
  1566.         dec     dword [esp+4]
  1567.         jns     .l2
  1568.         dec     ecx
  1569.         js      .l2
  1570.         inc     dword [edx+4]   ; new file block copied
  1571.         push    ebp
  1572.         lea     ebp, [esp+20]
  1573.         call    fat_entry_to_bdfe
  1574.         pop     ebp
  1575. .l2:
  1576.         add     edi, 0x20
  1577.         cmp     edi, ebx
  1578.         jb      .l1
  1579.         pop     eax
  1580.         inc     eax
  1581.         dec     dword [esp+4]
  1582.         jnz     .new_sector
  1583.         mov     eax, [ebp+FAT.cluster_tmp]
  1584.         test    eax, eax
  1585.         jz      .done
  1586.         call    get_FAT
  1587.         jc      .notfound2
  1588.         cmp     eax, 2
  1589.         jb      .done
  1590.         cmp     eax, [ebp+FAT.fatRESERVED]
  1591.         jae     .done
  1592.         push    eax
  1593.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1594.         mov     [esp+8], eax
  1595.         pop     eax
  1596.         pop     ebx
  1597.         add     esp, 4
  1598.         jmp     .new_cluster
  1599.  
  1600. .notfound2:
  1601.         add     esp, 8
  1602. .notfound:
  1603.         add     esp, 262*2+4
  1604.         push    ERROR_DEVICE
  1605.         jmp     @f
  1606.  
  1607. .done:
  1608.         add     esp, 262*2+12
  1609.         pushd   0
  1610.         dec     ecx
  1611.         js      @f
  1612.         mov     byte [esp], ERROR_END_OF_FILE
  1613. @@:
  1614.         mov     ebx, [edx+4]
  1615. .ret:
  1616.         call    fat_unlock
  1617.         pop     eax
  1618.         ret
  1619.  
  1620. .error:
  1621.         push    eax
  1622.         xor     ebx, ebx
  1623.         jmp     .ret
  1624.  
  1625. .accessDenied:
  1626.         push    ERROR_ACCESS_DENIED
  1627.         xor     ebx, ebx
  1628.         jmp     .ret
  1629.  
  1630. fat1x_root_next:
  1631.         push    ecx
  1632.         lea     ecx, [ebp+FAT.buffer+0x200-0x20]
  1633.         cmp     edi, ecx
  1634.         jae     fat1x_root_next_sector
  1635.         add     edi, 0x20
  1636. @@:
  1637.         pop     ecx
  1638.         ret
  1639.  
  1640. fat1x_root_next_write:
  1641.         push    ecx
  1642.         lea     ecx, [ebp+FAT.buffer+0x200]
  1643.         cmp     edi, ecx
  1644.         jc      @b
  1645.         call    fat1x_root_end_write
  1646. fat1x_root_next_sector:
  1647.         push    [ebp+FAT.longname_sec2]
  1648.         pop     [ebp+FAT.longname_sec1]
  1649.         mov     ecx, [eax+4]
  1650.         push    ecx
  1651.         add     ecx, [ebp+FAT.ROOT_START]
  1652.         mov     [ebp+FAT.longname_sec2], ecx
  1653.         pop     ecx
  1654.         inc     ecx
  1655.         mov     [eax+4], ecx
  1656.         cmp     ecx, [ebp+FAT.ROOT_SECTORS]
  1657.         jnc     fat_notroot_next_err
  1658.         pop     ecx
  1659. fat1x_root_first:
  1660.         mov     eax, [eax+4]
  1661.         add     eax, [ebp+FAT.ROOT_START]
  1662.         push    ebx
  1663.         lea     edi, [ebp+FAT.buffer]
  1664.         mov     ebx, edi
  1665.         call    fs_read32_sys
  1666.         pop     ebx
  1667.         test    eax, eax
  1668.         jz      @f
  1669.         movi    eax, ERROR_DEVICE
  1670.         stc
  1671. @@:
  1672.         ret
  1673.  
  1674. fat1x_root_begin_write:
  1675.         push    edi eax
  1676.         call    fat1x_root_first
  1677.         pop     eax edi
  1678.         ret
  1679.  
  1680. fat1x_root_end_write:
  1681.         pusha
  1682.         mov     eax, [eax+4]
  1683.         add     eax, [ebp+FAT.ROOT_START]
  1684.         lea     ebx, [ebp+FAT.buffer]
  1685.         call    fs_write32_sys
  1686.         popa
  1687.         ret
  1688.  
  1689. fat_notroot_next:
  1690.         push    ecx
  1691.         lea     ecx, [ebp+FAT.buffer+0x200-0x20]
  1692.         cmp     edi, ecx
  1693.         jae     fat_notroot_next_sector
  1694.         add     edi, 0x20
  1695. @@:
  1696.         pop     ecx
  1697.         ret
  1698.  
  1699. fat_notroot_next_write:
  1700.         push    ecx
  1701.         lea     ecx, [ebp+FAT.buffer+0x200]
  1702.         cmp     edi, ecx
  1703.         jc      @b
  1704.         push    eax
  1705.         call    fat_notroot_end_write
  1706.         pop     eax
  1707. fat_notroot_next_sector:
  1708.         push    [ebp+FAT.longname_sec2]
  1709.         pop     [ebp+FAT.longname_sec1]
  1710.         push    eax
  1711.         call    fat_get_sector
  1712.         mov     [ebp+FAT.longname_sec2], eax
  1713.         pop     eax
  1714.         mov     ecx, [eax+4]
  1715.         inc     ecx
  1716.         cmp     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1717.         jae     fat_notroot_next_cluster
  1718.         mov     [eax+4], ecx
  1719.         jmp     @f
  1720.  
  1721. fat_notroot_next_err:
  1722.         pop     ecx
  1723.         movi    eax, ERROR_FILE_NOT_FOUND
  1724. fat1x_root_extend_dir:
  1725.         stc
  1726.         ret
  1727.  
  1728. fat_notroot_next_cluster:
  1729.         push    eax
  1730.         mov     eax, [eax]
  1731.         call    get_FAT
  1732.         mov     ecx, eax
  1733.         pop     eax
  1734.         jc      fat_notroot_first.deverr
  1735.         cmp     ecx, 2
  1736.         jb      fat_notroot_next_err
  1737.         cmp     ecx, [ebp+FAT.fatRESERVED]
  1738.         jae     fat_notroot_next_err
  1739.         mov     [eax], ecx
  1740.         and     dword [eax+4], 0
  1741. @@:
  1742.         pop     ecx
  1743. fat_notroot_first:
  1744.         call    fat_get_sector
  1745.         push    ebx
  1746.         lea     edi, [ebp+FAT.buffer]
  1747.         mov     ebx, edi
  1748.         call    fs_read32_sys
  1749.         pop     ebx
  1750.         test    eax, eax
  1751.         jz      .ret ; CF=0
  1752.         push    ecx
  1753. .deverr:
  1754.         pop     ecx
  1755.         mov     eax, ERROR_DEVICE
  1756.         stc
  1757. .ret:
  1758.         ret
  1759.  
  1760. fat_notroot_begin_write:
  1761.         push    eax edi
  1762.         call    fat_notroot_first
  1763.         pop     edi eax
  1764.         ret
  1765.  
  1766. fat_notroot_end_write:
  1767.         call    fat_get_sector
  1768.         push    ebx
  1769.         lea     ebx, [ebp+FAT.buffer]
  1770.         call    fs_write32_sys
  1771.         pop     ebx
  1772.         ret
  1773.  
  1774. fat_notroot_extend_dir.writeerr:
  1775.         pop     edx
  1776. @@:
  1777.         pop     eax
  1778.         ret
  1779.  
  1780. fat_notroot_extend_dir:
  1781.         push    eax
  1782.         call    get_free_FAT
  1783.         jc      @b
  1784.         push    edx
  1785.         mov     edx, [ebp+FAT.fatEND]
  1786.         call    set_FAT
  1787.         jc      .writeerr
  1788.         mov     edx, eax
  1789.         mov     eax, [esp+4]
  1790.         mov     eax, [eax]
  1791.         push    edx
  1792.         call    set_FAT
  1793.         pop     edx
  1794.         jc      .writeerr
  1795.         push    ecx
  1796.         or      ecx, -1
  1797.         call    add_disk_free_space
  1798.         mov     ecx, 512/4
  1799.         lea     edi, [ebp+FAT.buffer]
  1800.         push    edi
  1801.         xor     eax, eax
  1802.         rep stosd
  1803.         pop     edi
  1804.         pop     ecx
  1805.         mov     eax, [esp+4]
  1806.         mov     [eax], edx
  1807.         and     dword [eax+4], 0
  1808.         pop     edx
  1809.         mov     eax, [eax]
  1810.         dec     eax
  1811.         dec     eax
  1812.         push    ebx ecx
  1813.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1814.         imul    eax, ecx
  1815.         add     eax, [ebp+FAT.DATA_START]
  1816.         mov     ebx, edi
  1817. @@:
  1818.         push    eax
  1819.         call    fs_write32_sys
  1820.         pop     eax
  1821.         inc     eax
  1822.         loop    @b
  1823.         pop     ecx ebx eax
  1824.         clc
  1825.         ret
  1826.  
  1827. fat_get_sector:
  1828.         push    ecx
  1829.         mov     ecx, [eax]
  1830.         dec     ecx
  1831.         dec     ecx
  1832.         imul    ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1833.         add     ecx, [ebp+FAT.DATA_START]
  1834.         add     ecx, [eax+4]
  1835.         mov     eax, ecx
  1836.         pop     ecx
  1837.         ret
  1838.  
  1839. ;----------------------------------------------------------------
  1840. fat_CreateFolder:
  1841.         mov     [ebp+FAT.createOption], 0
  1842.         jmp     @f
  1843.  
  1844. fat_CreateFile:
  1845.         mov     [ebp+FAT.createOption], 1
  1846. @@:
  1847.         call    fat_lock
  1848.         mov     ecx, [ebx+12]
  1849.         mov     edx, [ebx+16]
  1850. .rename:
  1851.         pushad
  1852.         xor     edi, edi
  1853.         push    esi
  1854. @@:
  1855.         lodsb
  1856.         test    al, al
  1857.         jz      @f
  1858.         cmp     al, '/'
  1859.         jnz     @b
  1860.         lea     edi, [esi-1]
  1861.         jmp     @b
  1862.  
  1863. @@:
  1864.         pop     esi
  1865.         test    edi, edi
  1866.         jnz     .noroot
  1867.         mov     edx, [ebp+FAT.ROOT_CLUSTER]
  1868.         cmp     [ebp+FAT.fs_type], 32
  1869.         jz      .pushnotroot
  1870.         xor     edx, edx
  1871.         push    edx
  1872.         push    fat1x_root_extend_dir
  1873.         push    fat1x_root_end_write
  1874.         push    fat1x_root_next_write
  1875.         push    fat1x_root_begin_write
  1876.         push    edx
  1877.         push    edx
  1878.         push    fat1x_root_first
  1879.         push    fat1x_root_next
  1880.         jmp     .common1
  1881.  
  1882. .retNotFound:
  1883.         movi    eax, ERROR_FILE_NOT_FOUND
  1884.         jmp     .ret1
  1885.  
  1886. .noAccess:
  1887.         movi    eax, ERROR_ACCESS_DENIED
  1888. .ret1:
  1889.         mov     [esp+28], eax
  1890.         call    fat_unlock
  1891.         popad
  1892.         xor     ebx, ebx
  1893.         ret
  1894.  
  1895. .full:
  1896.         movi    eax, ERROR_DISK_FULL
  1897.         jmp     .ret1
  1898.  
  1899. .noroot:
  1900.         cmp     byte [edi+1], 0
  1901.         jz      .noAccess
  1902. ; check existence
  1903.         mov     byte [edi], 0
  1904.         push    edi
  1905.         call    hd_find_lfn
  1906.         pop     esi
  1907.         mov     byte [esi], '/'
  1908.         jc      .retNotFound
  1909.         inc     esi
  1910.         test    byte [edi+11], 0x10
  1911.         jz      .noAccess   ; file
  1912.         mov     edx, [edi+20-2]
  1913.         mov     dx, [edi+26]
  1914.         movi    eax, ERROR_FS_FAIL
  1915.         cmp     edx, 2
  1916.         jb      .ret1
  1917. .pushnotroot:
  1918.         push    edx
  1919.         push    fat_notroot_extend_dir
  1920.         push    fat_notroot_end_write
  1921.         push    fat_notroot_next_write
  1922.         push    fat_notroot_begin_write
  1923.         push    0
  1924.         push    edx
  1925.         push    fat_notroot_first
  1926.         push    fat_notroot_next
  1927. .common1:
  1928.         call    fat_find_lfn
  1929.         jc      .notfound
  1930.         test    byte [edi+11], 10h
  1931.         jz      .exists_file
  1932. ; found directory
  1933.         add     esp, 36
  1934.         call    fat_unlock
  1935.         popad
  1936.         xor     eax, eax
  1937.         cmp     [ebp+FAT.createOption], 0
  1938.         jz      @f
  1939.         mov     al, ERROR_ACCESS_DENIED
  1940. @@:
  1941.         xor     ebx, ebx
  1942.         ret
  1943.  
  1944. .exists_file:
  1945.         cmp     [ebp+FAT.createOption], 1
  1946.         jz      @f
  1947.         add     esp, 36
  1948.         jmp     .noAccess
  1949.  
  1950. @@: ; delete FAT chain
  1951.         push    edi
  1952.         xor     eax, eax
  1953.         mov     dword [edi+28], eax     ; zero size
  1954.         xor     ecx, ecx
  1955.         mov     eax, [edi+20-2]
  1956.         mov     ax, [edi+26]
  1957.         mov     word [edi+20], cx
  1958.         mov     word [edi+26], cx
  1959.         test    eax, eax
  1960.         jz      .done1
  1961. @@:
  1962.         cmp     eax, [ebp+FAT.fatRESERVED]
  1963.         jae     .done1
  1964.         xor     edx, edx
  1965.         call    set_FAT
  1966.         mov     eax, edx
  1967.         jc      .done1
  1968.         inc     ecx
  1969.         jmp     @b
  1970.  
  1971. .short_name_found:
  1972.         pop     ecx edi esi
  1973.         call    fat_next_short_name
  1974.         jnc     .test_short_name_loop
  1975. .disk_full:
  1976.         add     esp, 12+36
  1977.         jmp     .full
  1978.  
  1979. .notfound:  ; generate short name
  1980.         call    fat_name_is_legal
  1981.         jc      @f
  1982.         add     esp, 36
  1983.         jmp     .retNotFound
  1984.  
  1985. @@:
  1986.         sub     esp, 12
  1987.         mov     edi, esp
  1988.         call    fat_gen_short_name
  1989. .test_short_name_loop:
  1990.         push    esi edi ecx
  1991.         mov     esi, edi
  1992.         lea     eax, [esp+12+12+8]
  1993.         mov     edx, [eax+24]
  1994.         mov     [eax], edx
  1995.         and     dword [eax+4], 0
  1996.         call    dword [eax-4]
  1997.         jc      .found
  1998. .test_short_name_entry:
  1999.         cmp     byte [edi+11], 0xF
  2000.         jz      .test_short_name_cont
  2001.         mov     ecx, 11
  2002.         push    esi edi
  2003.         repz cmpsb
  2004.         pop     edi esi
  2005.         jz      .short_name_found
  2006. .test_short_name_cont:
  2007.         lea     eax, [esp+12+12+8]
  2008.         call    dword [eax-8]
  2009.         jnc     .test_short_name_entry
  2010. .found:
  2011.         pop     ecx edi esi
  2012. ; now find space in directory
  2013. ; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
  2014.         mov     al, '~'
  2015.         push    ecx edi
  2016.         mov     ecx, 8
  2017.         repnz scasb
  2018.         movi    eax, 1     ; 1 entry
  2019.         jnz     .notilde
  2020. ; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
  2021.         xor     ecx, ecx
  2022.         push    esi
  2023. @@:
  2024.         call    utf8to16
  2025.         inc     ecx
  2026.         test    ax, ax
  2027.         jnz     @b
  2028.         pop     esi
  2029.         mov     eax, ecx
  2030.         add     eax, 12+13-1
  2031.         mov     ecx, 13
  2032.         cdq
  2033.         div     ecx
  2034. .notilde:
  2035.         push    -1
  2036.         push    -1
  2037.         push    -1
  2038. ; find <eax> successive entries in directory
  2039.         xor     ecx, ecx
  2040.         push    eax
  2041.         lea     eax, [esp+16+8+12+8]
  2042.         mov     edx, [eax+24]
  2043.         mov     [eax], edx
  2044.         and     dword [eax+4], 0
  2045.         call    dword [eax-4]
  2046.         pop     eax
  2047.         jnc     .scan_dir
  2048. .fsfrfe3:
  2049.         add     esp, 12+8+12+36
  2050.         movi    eax, ERROR_DEVICE
  2051.         jmp     .ret1
  2052.  
  2053. .scan_dir:
  2054.         cmp     byte [edi], 0
  2055.         jz      .free
  2056.         cmp     byte [edi], 0xE5
  2057.         jz      .free
  2058.         xor     ecx, ecx
  2059. .scan_cont:
  2060.         push    eax
  2061.         lea     eax, [esp+16+8+12+8]
  2062.         call    dword [eax-8]
  2063.         mov     edx, eax
  2064.         pop     eax
  2065.         jnc     .scan_dir
  2066.         cmp     edx, ERROR_DEVICE
  2067.         jz      .fsfrfe3
  2068.         push    eax
  2069.         lea     eax, [esp+16+8+12+8]
  2070.         call    dword [eax+20]          ; extend directory
  2071.         pop     eax
  2072.         jnc     .scan_dir
  2073.         add     esp, 12+8+12+36
  2074.         jmp     .full
  2075.  
  2076. .free:
  2077.         test    ecx, ecx
  2078.         jnz     @f
  2079.         mov     [esp], edi
  2080.         mov     ecx, [esp+12+8+12+8]
  2081.         mov     [esp+4], ecx
  2082.         mov     ecx, [esp+12+8+12+12]
  2083.         mov     [esp+8], ecx
  2084.         xor     ecx, ecx
  2085. @@:
  2086.         inc     ecx
  2087.         cmp     ecx, eax
  2088.         jb      .scan_cont
  2089. ; found!
  2090.         push    esi ecx
  2091. ; If creating a directory, allocate one data cluster or fail immediately if this is impossible.
  2092. ; This prevents from creating an invalid directory entry on a full disk.
  2093.         cmp     [ebp+FAT.createOption], 0
  2094.         jnz     .notFolder
  2095.         call    get_free_FAT
  2096.         jnc     @f
  2097.         add     esp, 8+12+8
  2098.         jmp     .disk_full
  2099.  
  2100. @@:
  2101.         mov     [esp+8+12+8+12+36+20], eax  ; store the cluster somewhere
  2102. .notFolder: ; calculate name checksum
  2103.         mov     esi, [esp+8+12]
  2104.         mov     ecx, 11
  2105.         xor     eax, eax
  2106. @@:
  2107.         ror     al, 1
  2108.         add     al, [esi]
  2109.         inc     esi
  2110.         loop    @b
  2111.         pop     ecx esi edi
  2112.         pop     dword [esp+8+12+12]
  2113.         pop     dword [esp+8+12+12]
  2114. ; edi points to first entry in free chunk
  2115.         dec     ecx
  2116.         jz      .nolfn
  2117.         push    esi eax
  2118.         lea     eax, [esp+8+8+12+8]
  2119.         call    dword [eax+8]   ; begin write
  2120.         mov     al, 40h
  2121. .writelfn:
  2122.         or      al, cl
  2123.         stosb
  2124.         mov     esi, [esp+4]
  2125.         push    ecx
  2126.         dec     ecx
  2127.         jz      @f
  2128.         imul    ecx, 13
  2129. .scroll:
  2130.         call    utf8to16
  2131.         loop    .scroll
  2132. @@:
  2133.         mov     cl, 5
  2134.         call    fat_read_symbols
  2135.         mov     ax, 0xF
  2136.         stosw
  2137.         mov     al, [esp+4]
  2138.         stosb
  2139.         mov     cl, 6
  2140.         call    fat_read_symbols
  2141.         xor     eax, eax
  2142.         stosw
  2143.         mov     cl, 2
  2144.         call    fat_read_symbols
  2145.         pop     ecx
  2146.         lea     eax, [esp+8+8+12+8]
  2147.         call    dword [eax+12]  ; next write
  2148.         xor     eax, eax
  2149.         loop    .writelfn
  2150.         pop     eax esi
  2151. .nolfn:
  2152.         pop     esi
  2153.         add     esp, 16
  2154.         mov     ecx, 11
  2155.         rep movsb
  2156.         cmp     [ebp+FAT.createOption], 2
  2157.         jz      .copy
  2158.         mov     word [edi], 20h         ; attributes
  2159.         sub     edi, 11
  2160.         mov     byte [edi+13], 0        ; tenths of a second at file creation time
  2161.         call    get_time_for_file
  2162.         mov     [edi+14], ax            ; creation time
  2163.         mov     [edi+22], ax            ; last write time
  2164.         call    get_date_for_file
  2165.         mov     [edi+16], ax            ; creation date
  2166.         mov     [edi+24], ax            ; last write date
  2167.         mov     [edi+18], ax            ; last access date
  2168.         mov     word [edi+20], cx       ; high word of cluster
  2169.         mov     word [edi+26], cx       ; low word of cluster - to be filled
  2170.         mov     dword [edi+28], ecx     ; file size - to be filled
  2171.         cmp     [ebp+FAT.createOption], 0
  2172.         jnz     .doit
  2173. ; create directory
  2174.         mov     byte [edi+11], 10h      ; attributes: folder
  2175.         mov     esi, edi
  2176.         mov     eax, [esp+36+20] ; extract saved cluster
  2177.         mov     [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space!
  2178.         push    ecx
  2179.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2180.         shl     ecx, 9
  2181.         push    ecx
  2182.         push    edi
  2183.         jmp     .doit2
  2184.  
  2185. .copy:
  2186.         lea     esi, [esp+72+11]
  2187.         mov     cl, 21
  2188.         rep movsb
  2189.         sub     edi, 32
  2190.         jmp     .doit
  2191.  
  2192. .done1:
  2193.         pop     edi
  2194.         call    get_time_for_file
  2195.         mov     [edi+22], ax
  2196.         call    get_date_for_file
  2197.         mov     [edi+24], ax
  2198.         mov     [edi+18], ax
  2199.         or      byte [edi+11], 20h      ; set 'archive' attribute
  2200. .doit:
  2201.         mov     esi, [esp+36+20]
  2202.         lea     eax, [esp+8]
  2203.         call    dword [eax+16]  ; flush directory
  2204.         push    ecx
  2205.         mov     ecx, [esp+4+36+24]
  2206.         xor     eax, eax
  2207.         test    ecx, ecx
  2208.         jz      .done
  2209.         push    ecx edi
  2210.         call    get_free_FAT
  2211.         jc      .diskfull
  2212. .doit2:
  2213.         push    eax
  2214.         mov     [edi+26], ax
  2215.         shr     eax, 16
  2216.         mov     [edi+20], ax
  2217.         lea     eax, [esp+16+8]
  2218.         call    dword [eax+16]  ; flush directory
  2219.         pop     eax
  2220.         mov     edx, [ebp+FAT.fatEND]
  2221.         call    set_FAT
  2222. .write_cluster:
  2223.         push    eax
  2224.         dec     eax
  2225.         dec     eax
  2226.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2227.         add     eax, [ebp+FAT.DATA_START]
  2228.         push    [ebp+FAT.SECTORS_PER_CLUSTER]
  2229. .write_sector:
  2230.         cmp     [ebp+FAT.createOption], 0
  2231.         jz      .writedir
  2232.         mov     ecx, 512
  2233.         cmp     dword [esp+12], ecx
  2234.         jb      .writeshort
  2235. ; we can write directly from given buffer
  2236.         mov     ebx, esi
  2237.         add     esi, ecx
  2238.         jmp     .writecommon
  2239.  
  2240. .writedir:
  2241.         push    512
  2242.         lea     edi, [ebp+FAT.buffer]
  2243.         mov     ebx, edi
  2244.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2245.         shl     ecx, 9
  2246.         cmp     ecx, [esp+16]
  2247.         jnz     .writedircont
  2248.         dec     dword [esp+20]
  2249.         push    esi
  2250.         mov     ecx, 32/4
  2251.         rep movsd
  2252.         pop     esi
  2253.         mov     dword [edi-32], '.   '
  2254.         mov     dword [edi-32+4], '    '
  2255.         mov     dword [edi-32+8], '    '
  2256.         mov     byte [edi-32+11], 10h
  2257.         push    esi
  2258.         mov     ecx, 32/4
  2259.         rep movsd
  2260.         pop     esi
  2261.         mov     dword [edi-32], '..  '
  2262.         mov     dword [edi-32+4], '    '
  2263.         mov     dword [edi-32+8], '    '
  2264.         mov     byte [edi-32+11], 10h
  2265.         mov     ecx, [esp+20+36]
  2266.         cmp     ecx, [ebp+FAT.ROOT_CLUSTER]
  2267.         jnz     @f
  2268.         xor     ecx, ecx
  2269. @@:
  2270.         mov     word [edi-32+26], cx
  2271.         shr     ecx, 16
  2272.         mov     [edi-32+20], cx
  2273.         jmp     .writedircont
  2274.  
  2275. .writeshort:
  2276.         mov     ecx, [esp+12]
  2277.         push    ecx
  2278.         lea     edi, [ebp+FAT.buffer]
  2279.         mov     ebx, edi
  2280.         rep movsb
  2281. .writedircont:
  2282.         lea     ecx, [ebp+FAT.buffer+0x200]
  2283.         sub     ecx, edi
  2284.         push    eax
  2285.         xor     eax, eax
  2286.         rep stosb
  2287.         pop     eax
  2288.         pop     ecx
  2289. .writecommon:
  2290.         push    eax
  2291.         call    fs_write32_app
  2292.         test    eax, eax
  2293.         pop     eax
  2294.         jnz     .writeerr
  2295.         inc     eax
  2296.         sub     dword [esp+12], ecx
  2297.         jz      .writedone
  2298.         dec     dword [esp]
  2299.         jnz     .write_sector
  2300.         pop     eax
  2301. ; allocate new cluster
  2302.         pop     eax
  2303.         mov     ecx, eax
  2304.         call    get_free_FAT
  2305.         jc      .diskfull
  2306.         mov     edx, [ebp+FAT.fatEND]
  2307.         call    set_FAT
  2308.         xchg    eax, ecx
  2309.         mov     edx, ecx
  2310.         call    set_FAT
  2311.         xchg    eax, ecx
  2312.         jmp     .write_cluster
  2313.  
  2314. .diskfull:
  2315.         mov     eax, ERROR_DISK_FULL
  2316.         jmp     .ret
  2317.  
  2318. .writeerr:
  2319.         pop     eax eax
  2320.         sub     esi, ecx
  2321.         mov     eax, ERROR_DEVICE
  2322.         jmp     .ret
  2323.  
  2324. .writedone:
  2325.         pop     eax eax
  2326.         xor     eax, eax
  2327. .ret:
  2328.         pop     edi ecx
  2329.         inc     ecx
  2330. .done:
  2331.         sub     esi, [esp+4+36+20]
  2332.         mov     [esp+4+36+28], eax
  2333.         mov     [esp+4+36+16], esi
  2334.         jecxz   @f
  2335.         lea     eax, [esp+12]
  2336.         call    dword [eax+8]
  2337.         mov     [edi+28], esi
  2338.         call    dword [eax+16]
  2339. @@:
  2340.         lea     eax, [esi+511]
  2341.         shr     eax, 9
  2342.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2343.         lea     eax, [eax+ecx-1]
  2344.         xor     edx, edx
  2345.         div     ecx
  2346.         pop     ecx
  2347.         sub     ecx, eax
  2348.         call    add_disk_free_space
  2349.         add     esp, 36
  2350.         cmp     [ebp+FAT.createOption], 2
  2351.         jz      @f
  2352.         call    update_disk
  2353.         call    fat_unlock
  2354. @@:
  2355.         popad
  2356.         ret
  2357.  
  2358. @@:
  2359.         or      eax, -1
  2360.         rep stosw
  2361.         ret
  2362.  
  2363. fat_read_symbols:
  2364.         test    esi, esi
  2365.         jz      @b
  2366.         call    utf8to16
  2367.         stosw
  2368.         test    ax, ax
  2369.         jnz     @f
  2370.         xor     esi, esi
  2371. @@:
  2372.         loop    fat_read_symbols
  2373.         ret
  2374.  
  2375. ;----------------------------------------------------------------
  2376. fat_Write:
  2377.         call    fat_lock
  2378.         call    hd_find_lfn
  2379.         jc      .error
  2380.         cmp     dword [ebx+8], 0
  2381.         jnz     .eof    ; FAT does not support files larger than 4GB
  2382.         mov     ecx, [ebx+12]
  2383.         mov     edx, [ebx+16]
  2384.         mov     ebx, [ebx+4]
  2385. ; now edi points to direntry, ebx=start byte to write,
  2386. ; ecx=number of bytes to write, edx=data pointer
  2387. ; extend file if needed
  2388.         add     ecx, ebx
  2389.         jc      .eof    ; FAT does not support files larger than 4GB
  2390.         push    edx
  2391.         push    eax     ; save directory sector
  2392.         push    0       ; return value=0
  2393.         call    get_time_for_file
  2394.         mov     [edi+22], ax            ; last write time
  2395.         call    get_date_for_file
  2396.         mov     [edi+24], ax            ; last write date
  2397.         mov     [edi+18], ax            ; last access date
  2398.         push    dword [edi+28]          ; save current file size
  2399.         cmp     ecx, [edi+28]
  2400.         jbe     .length_ok
  2401.         cmp     ecx, ebx
  2402.         jz      .length_ok
  2403.         call    hd_extend_file
  2404.         jnc     .length_ok
  2405.         mov     [esp+4], eax
  2406. ; hd_extend_file can return three error codes: FAT table error, device error or disk full.
  2407. ; First two cases are fatal errors, in third case we may write some data
  2408.         cmp     al, ERROR_DISK_FULL
  2409.         jnz     @f
  2410. ; correct number of bytes to write
  2411.         mov     ecx, [edi+28]
  2412.         cmp     ecx, ebx
  2413.         ja      .length_ok
  2414.         push    0
  2415. .ret:
  2416.         pop     eax eax eax ecx ecx
  2417.         sub     edx, ecx
  2418.         push    eax edx
  2419.         call    update_disk
  2420.         pop     ebx
  2421. @@:
  2422.         call    fat_unlock
  2423.         pop     eax
  2424.         ret
  2425.  
  2426. .error:
  2427.         push    eax
  2428.         jmp     @b
  2429.  
  2430. .eof:
  2431.         push    ERROR_END_OF_FILE
  2432.         xor     ebx, ebx
  2433.         jmp     @b
  2434.  
  2435. .device_err2:
  2436.         pop     ecx
  2437. .device_err:
  2438.         mov     byte [esp+8], ERROR_DEVICE
  2439.         jmp     .ret
  2440.  
  2441. .fat_err:
  2442.         mov     byte [esp+8], ERROR_FS_FAIL
  2443.         jmp     .ret
  2444.  
  2445. .length_ok:
  2446.         mov     esi, [edi+28]
  2447.         mov     eax, [edi+20-2]
  2448.         mov     ax, [edi+26]
  2449.         mov     edi, eax        ; edi=current cluster
  2450.         push    0               ; current sector in cluster
  2451. ; save directory
  2452.         mov     eax, [esp+12]
  2453.         push    ebx
  2454.         lea     ebx, [ebp+FAT.buffer]
  2455.         call    fs_write32_sys
  2456.         pop     ebx
  2457.         test    eax, eax
  2458.         jnz     .device_err
  2459. ; now ebx=start pos, ecx=end pos, both lie inside file
  2460.         sub     ecx, ebx
  2461.         jz      .ret
  2462. .write_loop:
  2463. ; skip unmodified sectors
  2464.         cmp     dword [esp+4], 0x200
  2465.         jb      .modify
  2466.         sub     ebx, 0x200
  2467.         jae     .skip
  2468.         add     ebx, 0x200
  2469. .modify:
  2470. ; get length of data in current sector
  2471.         push    ecx
  2472.         sub     ebx, 0x200
  2473.         jb      .hasdata
  2474.         neg     ebx
  2475.         xor     ecx, ecx
  2476.         jmp     @f
  2477. .hasdata:
  2478.         neg     ebx
  2479.         cmp     ecx, ebx
  2480.         jbe     @f
  2481.         mov     ecx, ebx
  2482. @@:
  2483. ; get current sector number
  2484.         mov     eax, edi
  2485.         dec     eax
  2486.         dec     eax
  2487.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2488.         add     eax, [ebp+FAT.DATA_START]
  2489.         add     eax, [esp+4]
  2490. ; load sector if needed
  2491.         cmp     dword [esp+8], 0        ; we don't need to read uninitialized data
  2492.         jz      .noread
  2493.         cmp     ecx, 0x200      ; we don't need to read sector if it is fully rewritten
  2494.         jz      .noread
  2495.         cmp     ecx, esi        ; (same for the last sector)
  2496.         jz      .noread
  2497.         push    eax ebx
  2498.         lea     ebx, [ebp+FAT.buffer]
  2499.         call    fs_read32_app
  2500.         test    eax, eax
  2501.         pop     ebx eax
  2502.         jnz     .device_err2
  2503. .noread:
  2504. ; zero uninitialized data if file was extended (because hd_extend_file does not this)
  2505.         push    eax ecx edi
  2506.         xor     eax, eax
  2507.         mov     ecx, 0x200
  2508.         sub     ecx, [esp+8+12]
  2509.         jbe     @f
  2510.         lea     edi, [ebp+FAT.buffer]
  2511.         add     edi, [esp+8+12]
  2512.         rep stosb
  2513. @@:
  2514. ; zero uninitialized data in the last sector
  2515.         mov     ecx, 0x200
  2516.         sub     ecx, esi
  2517.         jbe     @f
  2518.         lea     edi, [ebp+FAT.buffer+esi]
  2519.         rep stosb
  2520. @@:
  2521.         pop     edi ecx
  2522. ; copy new data
  2523.         mov     eax, edx
  2524.         neg     ebx
  2525.         jecxz   @f
  2526.         lea     ebx, [ebp+FAT.buffer+0x200+ebx]
  2527.         call    memmove
  2528.         xor     ebx, ebx
  2529. @@:
  2530.         pop     eax
  2531. ; save sector
  2532.         push    ebx
  2533.         lea     ebx, [ebp+FAT.buffer]
  2534.         call    fs_write32_app
  2535.         pop     ebx
  2536.         test    eax, eax
  2537.         jnz     .device_err2
  2538.         add     edx, ecx
  2539.         sub     [esp], ecx
  2540.         pop     ecx
  2541.         jz      .ret
  2542. .skip:
  2543. ; next sector
  2544.         pop     eax
  2545.         inc     eax
  2546.         push    eax
  2547.         cmp     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2548.         jb      @f
  2549.         and     dword [esp], 0
  2550.         mov     eax, edi
  2551.         call    get_FAT
  2552.         mov     edi, eax
  2553.         jc      .device_err
  2554.         cmp     edi, 2
  2555.         jb      .fat_err
  2556.         cmp     edi, [ebp+FAT.fatRESERVED]
  2557.         jae     .fat_err
  2558. @@:
  2559.         sub     esi, 0x200
  2560.         jae     @f
  2561.         xor     esi, esi
  2562. @@:
  2563.         sub     dword [esp+4], 0x200
  2564.         jae     @f
  2565.         and     dword [esp+4], 0
  2566. @@:
  2567.         jmp     .write_loop
  2568.  
  2569. hd_extend_file.zero_size:
  2570.         xor     eax, eax
  2571.         jmp     hd_extend_file.start_extend
  2572.  
  2573. ; extends file on hd to given size (new data area is undefined)
  2574. ; in: edi->direntry, ecx=new size
  2575. ; out: CF=0 => OK, eax=0
  2576. ;      CF=1 => error, eax=code (ERROR_FS_FAIL or ERROR_DISK_FULL or ERROR_DEVICE)
  2577. hd_extend_file:
  2578.         push    esi
  2579.         mov     esi, [ebp+FAT.SECTORS_PER_CLUSTER]
  2580.         imul    esi, [ebp+FAT.BYTES_PER_SECTOR]
  2581.         push    ecx
  2582. ; find the last cluster of file
  2583.         mov     eax, [edi+20-2]
  2584.         mov     ax, [edi+26]
  2585.         mov     ecx, [edi+28]
  2586.         jecxz   .zero_size
  2587. .last_loop:
  2588.         sub     ecx, esi
  2589.         jbe     .last_found
  2590.         call    get_FAT
  2591.         jnc     @f
  2592. .device_err:
  2593.         pop     ecx
  2594. .device_err2:
  2595.         pop     esi
  2596.         push    ERROR_DEVICE
  2597. .ret_err:
  2598.         pop     eax
  2599.         stc
  2600.         ret
  2601. @@:
  2602.         cmp     eax, 2
  2603.         jb      .fat_err
  2604.         cmp     eax, [ebp+FAT.fatRESERVED]
  2605.         jb      .last_loop
  2606. .fat_err:
  2607.         pop     ecx esi
  2608.         push    ERROR_FS_FAIL
  2609.         jmp     .ret_err
  2610. .last_found:
  2611.         push    eax
  2612.         call    get_FAT
  2613.         jnc     @f
  2614.         pop     eax
  2615.         jmp     .device_err
  2616. @@:
  2617.         cmp     eax, [ebp+FAT.fatRESERVED]
  2618.         pop     eax
  2619.         jb      .fat_err
  2620. ; set length to full number of clusters
  2621.         sub     [edi+28], ecx
  2622. .start_extend:
  2623.         pop     ecx
  2624. ; now do extend
  2625.         push    edx
  2626.         mov     edx, 2          ; start scan from cluster 2
  2627. .extend_loop:
  2628.         cmp     [edi+28], ecx
  2629.         jae     .extend_done
  2630. ; add new cluster
  2631.         push    eax
  2632.         call    get_free_FAT
  2633.         jc      .disk_full
  2634.         mov     edx, [ebp+FAT.fatEND]
  2635.         call    set_FAT
  2636.         mov     edx, eax
  2637.         pop     eax
  2638.         test    eax, eax
  2639.         jz      .first_cluster
  2640.         push    edx
  2641.         call    set_FAT
  2642.         pop     edx
  2643.         jmp     @f
  2644. .first_cluster:
  2645.         ror     edx, 16
  2646.         mov     [edi+20], dx
  2647.         ror     edx, 16
  2648.         mov     [edi+26], dx
  2649. @@:
  2650.         push    ecx
  2651.         mov     ecx, -1
  2652.         call    add_disk_free_space
  2653.         pop     ecx
  2654.         mov     eax, edx
  2655.         add     [edi+28], esi
  2656.         jmp     .extend_loop
  2657. .extend_done:
  2658.         mov     [edi+28], ecx
  2659.         pop     edx esi
  2660.         xor     eax, eax        ; CF=0
  2661.         ret
  2662. .device_err3:
  2663.         pop     edx
  2664.         jmp     .device_err2
  2665. .disk_full:
  2666.         pop     eax edx esi
  2667.         movi    eax, ERROR_DISK_FULL
  2668.         stc
  2669.         ret
  2670.  
  2671. ;----------------------------------------------------------------
  2672. fat_SetFileEnd:
  2673.         call    fat_lock
  2674.         call    hd_find_lfn
  2675.         jc      .reteax
  2676. ; must not be directory
  2677.         test    byte [edi+11], 10h
  2678.         jnz     .access_denied
  2679. ; file size must not exceed 4 Gb
  2680.         cmp     dword [ebx+8], 0
  2681.         jnz     .endOfFile
  2682.         push    eax     ; save directory sector
  2683. ; set file modification date/time to current
  2684.         call    get_time_for_file
  2685.         mov     [edi+22], ax    ; last write
  2686.         call    get_date_for_file
  2687.         mov     [edi+24], ax    ; last write
  2688.         mov     [edi+18], ax    ; last access
  2689.         mov     eax, [ebx+4]
  2690.         cmp     eax, [edi+28]
  2691.         jb      .truncate
  2692.         ja      .expand
  2693.         pop     eax
  2694.         lea     ebx, [ebp+FAT.buffer]
  2695.         call    fs_write32_sys
  2696.         test    eax, eax
  2697.         jnz     .errorDevice
  2698.         push    0
  2699.         jmp     .ret
  2700.  
  2701. .access_denied:
  2702.         push    ERROR_ACCESS_DENIED
  2703.         jmp     .ret
  2704.  
  2705. .endOfFile:
  2706.         push    ERROR_END_OF_FILE
  2707.         jmp     .ret
  2708.  
  2709. .errorDevice:
  2710.         push    ERROR_DEVICE
  2711.         jmp     .ret
  2712.  
  2713. .expand:
  2714.         push    ebx ebp ecx
  2715.         push    dword [edi+28]  ; save old size
  2716.         mov     ecx, eax
  2717.         call    hd_extend_file
  2718.         push    eax             ; return code
  2719.         jnc     .expand_ok
  2720.         cmp     al, ERROR_DISK_FULL
  2721.         jnz     .pop_ret
  2722. .expand_ok: ; save directory
  2723.         mov     eax, [edi+28]
  2724.         xchg    eax, [esp+20]
  2725.         lea     ebx, [ebp+FAT.buffer]
  2726.         call    fs_write32_sys
  2727.         test    eax, eax
  2728.         jnz     .pop_ret11
  2729.         mov     eax, [esp+20]
  2730.         sub     eax, [esp+4]
  2731.         cmp     eax, 1000001h
  2732.         jnc     .pop_ret
  2733.         mov     eax, [edi+20-2]
  2734.         mov     ax, [edi+26]
  2735.         mov     edi, eax
  2736.         test    edi, edi
  2737.         jz      .pop_ret
  2738. ; now zero new data
  2739.         push    0
  2740. ; edi=current cluster, [esp]=sector in cluster
  2741. ; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code
  2742. .zero_loop:
  2743.         cmp     edi, 2
  2744.         jb      .error_fat
  2745.         cmp     edi, [ebp+FAT.fatRESERVED]
  2746.         jae     .error_fat
  2747.         sub     dword [esp+8], 0x200
  2748.         jae     .next_cluster
  2749.         lea     eax, [edi-2]
  2750.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2751.         add     eax, [ebp+FAT.DATA_START]
  2752.         add     eax, [esp]
  2753.         cmp     dword [esp+8], -0x200
  2754.         jz      .noread
  2755.         push    eax
  2756.         lea     ebx, [ebp+FAT.buffer]
  2757.         call    fs_read32_app
  2758.         test    eax, eax
  2759.         pop     eax
  2760.         jnz     .err_next
  2761. .noread:
  2762.         mov     ecx, [esp+8]
  2763.         neg     ecx
  2764.         push    edi
  2765.         lea     edi, [ebp+FAT.buffer+0x200]
  2766.         add     edi, [esp+12]
  2767.         push    eax
  2768.         xor     eax, eax
  2769.         mov     [esp+16], eax
  2770.         rep stosb
  2771.         pop     eax
  2772.         pop     edi
  2773.         call    fs_write32_app
  2774.         test    eax, eax
  2775.         jz      .next_cluster
  2776. .err_next:
  2777.         mov     byte [esp+4], ERROR_DEVICE
  2778. .next_cluster:
  2779.         pop     eax
  2780.         sub     dword [esp+20], 0x200
  2781.         jbe     .pop_ret
  2782.         inc     eax
  2783.         push    eax
  2784.         cmp     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2785.         jb      .zero_loop
  2786.         and     dword [esp], 0
  2787.         mov     eax, edi
  2788.         call    get_FAT
  2789.         mov     edi, eax
  2790.         jnc     .zero_loop
  2791.         pop     eax
  2792. .pop_ret11:
  2793.         mov     byte [esp], ERROR_DEVICE
  2794. .pop_ret:
  2795.         call    update_disk
  2796.         pop     eax ecx ecx ebp ebx ecx
  2797. .reteax:
  2798.         push    eax
  2799. .ret:
  2800.         call    fat_unlock
  2801.         pop     eax
  2802.         ret
  2803.  
  2804. .error_fat:
  2805.         pop     eax
  2806.         mov     byte [esp], ERROR_FS_FAIL
  2807.         jmp     .pop_ret
  2808.  
  2809. .error_fat2:
  2810.         pop     eax ecx eax
  2811.         call    update_disk
  2812.         push    ERROR_FS_FAIL
  2813.         jmp     .ret
  2814.  
  2815. .truncate:
  2816.         mov     [edi+28], eax
  2817.         push    ecx
  2818.         mov     ecx, [edi+20-2]
  2819.         mov     cx, [edi+26]
  2820.         push    eax
  2821.         test    eax, eax
  2822.         jz      .zero_size
  2823. @@: ; find new last cluster
  2824.         cmp     ecx, 2
  2825.         jb      .error_fat2
  2826.         cmp     ecx, [ebp+FAT.fatRESERVED]
  2827.         jae     .error_fat2
  2828.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2829.         shl     eax, 9
  2830.         sub     [esp], eax
  2831.         jbe     @f
  2832.         mov     eax, ecx
  2833.         call    get_FAT
  2834.         mov     ecx, eax
  2835.         jnc     @b
  2836. .device_err3:
  2837.         pop     eax ecx eax
  2838.         call    update_disk
  2839.         push    ERROR_DEVICE
  2840.         jmp     .ret
  2841.  
  2842. @@:
  2843. ; we will zero data at the end of last sector - remember it
  2844.         push    ecx
  2845. ; terminate FAT chain
  2846.         push    edx
  2847.         mov     eax, ecx
  2848.         mov     edx, [ebp+FAT.fatEND]
  2849.         call    set_FAT
  2850.         mov     eax, edx
  2851.         pop     edx
  2852.         jnc     @f
  2853. .device_err4:
  2854.         pop     ecx
  2855.         jmp     .device_err3
  2856.  
  2857. .zero_size:
  2858.         and     word [edi+20], 0
  2859.         and     word [edi+26], 0
  2860.         push    0
  2861.         mov     eax, ecx
  2862. @@:
  2863. ; delete FAT chain
  2864.         call    clear_cluster_chain
  2865.         jc      .device_err4
  2866. ; save directory
  2867.         mov     eax, [esp+12]
  2868.         push    ebx
  2869.         lea     ebx, [ebp+FAT.buffer]
  2870.         call    fs_write32_sys
  2871.         pop     ebx
  2872.         test    eax, eax
  2873.         jnz     .device_err4
  2874. ; zero last sector, ignore errors
  2875.         pop     ecx
  2876.         pop     eax
  2877.         dec     ecx
  2878.         imul    ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2879.         add     ecx, [ebp+FAT.DATA_START]
  2880.         push    eax
  2881.         sar     eax, 9
  2882.         add     ecx, eax
  2883.         pop     eax
  2884.         and     eax, 0x1FF
  2885.         jz      .truncate_done
  2886.         push    ebx eax
  2887.         mov     eax, ecx
  2888.         lea     ebx, [ebp+FAT.buffer]
  2889.         call    fs_read32_app
  2890.         pop     eax
  2891.         lea     edi, [ebp+FAT.buffer+eax]
  2892.         push    ecx
  2893.         mov     ecx, 0x200
  2894.         sub     ecx, eax
  2895.         xor     eax, eax
  2896.         rep stosb
  2897.         pop     eax
  2898.         call    fs_write32_app
  2899.         pop     ebx
  2900. .truncate_done:
  2901.         pop     ecx eax
  2902.         call    update_disk
  2903.         call    fat_unlock
  2904.         xor     eax, eax
  2905.         ret
  2906.  
  2907. ;----------------------------------------------------------------
  2908. fat_GetFileInfo:
  2909.         cmp     byte [esi], 0
  2910.         jz      .volume
  2911.         call    fat_lock
  2912.         call    hd_find_lfn
  2913.         jc      @f
  2914.         push    ebp
  2915.         xor     ebp, ebp
  2916.         mov     esi, [ebx+16]
  2917.         mov     dword [esi+4], ebp
  2918.         call    fat_entry_to_bdfe2
  2919.         pop     ebp
  2920.         xor     eax, eax
  2921. @@:
  2922.         push    eax
  2923.         call    fat_unlock
  2924.         pop     eax
  2925. @@:
  2926.         ret
  2927.  
  2928. .volume:
  2929.         mov     eax, dword[ebp+FAT.Length]
  2930.         mov     edx, dword[ebp+FAT.Length+4]
  2931.         mov     edi, [ebx+16]
  2932.         shld    edx, eax, 9
  2933.         shl     eax, 9
  2934.         mov     [edi+36], edx
  2935.         mov     [edi+32], eax
  2936.         mov     eax, [ebx+8]
  2937.         mov     byte [edi], 8
  2938.         mov     [edi+4], eax
  2939.         test    eax, eax
  2940.         jz      @b
  2941.         lea     esi, [ebp+FAT.volumeLabel]
  2942.         mov     ecx, 11
  2943. @@:
  2944.         mov     byte [esi+ecx], 0
  2945.         dec     ecx
  2946.         jz      @f
  2947.         cmp     byte [esi+ecx], ' '
  2948.         jz      @b
  2949. @@:
  2950.         mov     cl, 12
  2951.         add     edi, 40
  2952.         cmp     eax, 2
  2953.         jz      @f
  2954.         rep movsb
  2955.         xor     eax, eax
  2956.         ret
  2957.  
  2958. @@:
  2959.         lodsb
  2960.         stosw
  2961.         loop    @b
  2962.         ret
  2963.  
  2964. ;----------------------------------------------------------------
  2965. fat_SetFileInfo:
  2966.         call    fat_lock
  2967.         call    hd_find_lfn
  2968.         jc      @f
  2969.         push    eax
  2970.         mov     edx, [ebx+16]
  2971.         call    bdfe_to_fat_entry
  2972.         pop     eax
  2973.         lea     ebx, [ebp+FAT.buffer]
  2974.         call    fs_write32_sys
  2975.         call    update_disk
  2976.         xor     eax, eax
  2977. @@:
  2978.         push    eax
  2979.         call    fat_unlock
  2980.         pop     eax
  2981.         ret
  2982.  
  2983. ;----------------------------------------------------------------
  2984. fat_Delete:
  2985.         call    fat_lock
  2986.         and     [ebp+FAT.longname_sec1], 0
  2987.         and     [ebp+FAT.longname_sec2], 0
  2988.         call    hd_find_lfn
  2989.         jc      .notFound
  2990.         cmp     dword [edi], '.   '
  2991.         jz      .access_denied2
  2992.         cmp     dword [edi], '..  '
  2993.         jz      .access_denied2
  2994.         test    byte [edi+11], 10h
  2995.         jz      .dodel
  2996. ; we can delete only empty folders!
  2997.         pushad
  2998.         mov     esi, [edi+20-2]
  2999.         mov     si, [edi+26]
  3000.         xor     ecx, ecx
  3001.         lea     eax, [esi-2]
  3002.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  3003.         add     eax, [ebp+FAT.DATA_START]
  3004.         lea     ebx, [ebp+FAT.buffer]
  3005.         call    fs_read32_sys
  3006.         test    eax, eax
  3007.         jnz     .err1
  3008.         lea     eax, [ebx+0x200]
  3009.         add     ebx, 2*0x20
  3010. .checkempty:
  3011.         cmp     byte [ebx], 0
  3012.         jz      .empty
  3013.         cmp     byte [ebx], 0xE5
  3014.         jnz     .notempty
  3015.         add     ebx, 0x20
  3016.         cmp     ebx, eax
  3017.         jb      .checkempty
  3018.         inc     ecx
  3019.         cmp     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  3020.         jb      @f
  3021.         mov     eax, esi
  3022.         call    get_FAT
  3023.         jc      .err1
  3024.         cmp     eax, 2
  3025.         jb      .error_fat
  3026.         cmp     eax, [ebp+FAT.fatRESERVED]
  3027.         jae     .empty
  3028.         mov     esi, eax
  3029.         xor     ecx, ecx
  3030. @@:
  3031.         lea     eax, [esi-2]
  3032.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  3033.         add     eax, [ebp+FAT.DATA_START]
  3034.         add     eax, ecx
  3035.         lea     ebx, [ebp+FAT.buffer]
  3036.         call    fs_read32_sys
  3037.         test    eax, eax
  3038.         lea     eax, [ebx+0x200]
  3039.         jz      .checkempty
  3040. .err1:
  3041.         popad
  3042. .err2:
  3043.         push    ERROR_DEVICE
  3044. .ret:
  3045.         call    fat_unlock
  3046.         pop     eax
  3047.         ret
  3048.  
  3049. .notFound:
  3050.         push    ERROR_FILE_NOT_FOUND
  3051.         jmp     .ret
  3052.  
  3053. .error_fat:
  3054.         popad
  3055.         push    ERROR_FS_FAIL
  3056.         jmp     .ret
  3057.  
  3058. .notempty:
  3059.         popad
  3060. .access_denied2:
  3061.         push    ERROR_ACCESS_DENIED
  3062.         jmp     .ret
  3063.  
  3064. .empty:
  3065.         popad
  3066.         push    eax ebx
  3067.         lea     ebx, [ebp+FAT.buffer]
  3068.         call    fs_read32_sys
  3069.         test    eax, eax
  3070.         pop     ebx eax
  3071.         jnz     .err2
  3072. .dodel:
  3073.         push    eax
  3074.         mov     eax, [edi+20-2]
  3075.         mov     ax, [edi+26]
  3076.         xchg    eax, [esp]
  3077. ; delete folder entry
  3078.         mov     byte [edi], 0xE5
  3079. ; delete LFN (if present)
  3080. .lfndel:
  3081.         lea     edx, [ebp+FAT.buffer]
  3082.         cmp     edi, edx
  3083.         ja      @f
  3084.         cmp     [ebp+FAT.longname_sec2], 0
  3085.         jz      .lfndone
  3086.         push    [ebp+FAT.longname_sec2]
  3087.         push    [ebp+FAT.longname_sec1]
  3088.         pop     [ebp+FAT.longname_sec2]
  3089.         and     [ebp+FAT.longname_sec1], 0
  3090.         push    ebx
  3091.         mov     ebx, edx
  3092.         call    fs_write32_sys
  3093.         mov     eax, [esp+4]
  3094.         call    fs_read32_sys
  3095.         pop     ebx
  3096.         pop     eax
  3097.         lea     edi, [ebp+FAT.buffer+0x200]
  3098. @@:
  3099.         sub     edi, 0x20
  3100.         cmp     byte [edi], 0xE5
  3101.         jz      .lfndone
  3102.         cmp     byte [edi+11], 0xF
  3103.         jnz     .lfndone
  3104.         mov     byte [edi], 0xE5
  3105.         jmp     .lfndel
  3106. .lfndone:
  3107.         push    ebx
  3108.         lea     ebx, [ebp+FAT.buffer]
  3109.         call    fs_write32_sys
  3110.         pop     ebx
  3111. ; delete FAT chain
  3112.         pop     eax
  3113.         call    clear_cluster_chain
  3114.         call    update_disk
  3115.         call    fat_unlock
  3116.         xor     eax, eax
  3117.         ret
  3118.  
  3119. ;----------------------------------------------------------------
  3120. fat_Rename:
  3121. ; in: edi -> new path string in UTF-8
  3122.         push    esi edi
  3123.         call    fat_lock
  3124.         call    hd_find_lfn
  3125.         pop     ebx
  3126.         jc      .error
  3127.         sub     esp, 32
  3128.         mov     esi, edi
  3129.         mov     edi, esp
  3130.         mov     ecx, 8
  3131.         rep movsd
  3132.         mov     [ebp+FAT.createOption], 2
  3133.         mov     esi, ebx
  3134.         call    fat_CreateFile.rename
  3135.         add     esp, 32
  3136.         pop     esi
  3137.         test    eax, eax
  3138.         jnz     .ret
  3139.         push    eax
  3140.         mov     [ebp+FAT.longname_sec1], eax
  3141.         mov     [ebp+FAT.longname_sec2], eax
  3142.         call    hd_find_lfn
  3143.         jc      .error
  3144.         mov     byte [edi], 0xE5
  3145.         jmp     fat_Delete.lfndel
  3146.  
  3147. .error:
  3148.         push    eax
  3149.         call    fat_unlock
  3150.         pop     eax ebx
  3151. .ret:
  3152.         ret
  3153.