Subversion Repositories Kolibri OS

Rev

Rev 6876 | Rev 6939 | Go to most recent revision | 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: 6917 $
  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 equ 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.         jc      .ret
  598. @@:
  599.         mov     [ebp+FAT.fat_in_cache], eax
  600.         call    fs_read32_sys
  601.         test    eax, eax
  602.         jne     .error
  603. .inCache:
  604.         cmp     [ebp+FAT.fs_type], 16
  605.         jne     .test32
  606.         xchg    [ebx+esi], dx   ; save new value and get old value
  607.         jmp     .write
  608.  
  609. .test32:
  610.         mov     eax, [ebp+FAT.fatMASK]
  611.         and     edx, eax
  612.         xor     eax, -1         ; mask for high bits
  613.         and     eax, [ebx+esi]  ; get high 4 bits
  614.         or      eax, edx
  615.         mov     edx, [ebx+esi]  ; get old value
  616.         mov     [ebx+esi], eax  ; save new value
  617. .write:
  618.         mov     [ebp+FAT.fat_change], 1
  619.         and     edx, [ebp+FAT.fatMASK]
  620. .ret:
  621.         pop     esi ebx eax
  622.         ret
  623.  
  624. .error:
  625.         stc
  626.         jmp     .ret
  627.  
  628. .FAT12:
  629.         test    edx, 0xF000
  630.         jnz     .error
  631.         mov     ebx, [ebp+FAT.fat12_unpacked_ptr]
  632.         xchg    [ebx+eax*2], dx
  633.         mov     [ebp+FAT.fat_change], 1
  634.         jmp     .ret
  635.  
  636. get_FAT:
  637. ; in: eax = cluster
  638. ; out: eax = next cluster, CF=1 -> error
  639.         push    ebx esi
  640.         cmp     [ebp+FAT.fs_type], 12
  641.         je      .FAT12
  642.         cmp     [ebp+FAT.fs_type], 16
  643.         je      @f
  644.         add     eax, eax
  645. @@:
  646.         add     eax, eax
  647.         mov     esi, 511
  648.         and     esi, eax
  649.         shr     eax, 9
  650.         add     eax, [ebp+FAT.FAT_START]
  651.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  652.         cmp     eax, [ebp+FAT.fat_in_cache]
  653.         je      .inCache
  654.         cmp     [ebp+FAT.fat_change], 0
  655.         je      @f
  656.         call    write_fat_sector
  657.         jc      .ret
  658. @@:
  659.         mov     [ebp+FAT.fat_in_cache], eax
  660.         call    fs_read32_sys
  661.         test    eax, eax
  662.         jnz     .error
  663. .inCache:
  664.         mov     eax, [ebx+esi]
  665.         and     eax, [ebp+FAT.fatMASK]
  666. .ret:
  667.         pop     esi ebx
  668.         ret
  669.  
  670. .error:
  671.         stc
  672.         jmp     .ret
  673.  
  674. .FAT12:
  675.         mov     ebx, [ebp+FAT.fat12_unpacked_ptr]
  676.         movzx   eax, word [ebx+eax*2]
  677.         jmp     .ret
  678.  
  679. get_free_FAT:
  680. ; out: eax = number of first free cluster, CF=1 -> disk full
  681.         push    ecx
  682.         mov     ecx, [ebp+FAT.LAST_CLUSTER]
  683.         mov     eax, [ebp+FAT.fatStartScan]
  684.         cmp     [ebp+FAT.fs_type], 12
  685.         jz      get_free_FAT12
  686.         dec     ecx
  687.         cmp     eax, 2
  688.         jb      .reset
  689. .test:
  690.         cmp     eax, [ebp+FAT.LAST_CLUSTER]
  691.         jbe     .inRange
  692. .reset:
  693.         mov     eax, 2
  694. .inRange:
  695.         push    eax
  696.         call    get_FAT
  697.         jc      @f
  698.         test    eax, eax
  699.         pop     eax
  700.         je      .found
  701.         inc     eax
  702.         dec     ecx
  703.         jnz     .test
  704. .notFound:
  705.         pop     ecx
  706.         stc
  707.         ret
  708.  
  709. @@:
  710.         pop     eax
  711.         jmp     .notFound
  712.  
  713. .found:
  714.         lea     ecx, [eax+1]
  715.         mov     [ebp+FAT.fatStartScan], ecx
  716.         pop     ecx
  717.         clc
  718.         ret
  719.  
  720. get_free_FAT12:
  721.         push    edx edi
  722.         mov     edi, [ebp+FAT.fat12_unpacked_ptr]
  723.         cmp     eax, 2
  724.         jb      .reset
  725.         cmp     eax, ecx
  726.         jbe     @f
  727. .reset:
  728.         mov     eax, 2
  729. @@:
  730.         mov     edx, eax
  731.         lea     edi, [edi+eax*2]
  732.         sub     ecx, eax
  733.         inc     ecx
  734.         xor     eax, eax
  735.         repnz scasw
  736.         jz      .found
  737.         cmp     edx, 2
  738.         jz      .notfound
  739.         mov     edi, [ebp+FAT.fat12_unpacked_ptr]
  740.         lea     ecx, [edx-2]
  741.         repnz scasw
  742.         jnz     .notfound
  743. .found:
  744.         sub     edi, [ebp+FAT.fat12_unpacked_ptr]
  745.         shr     edi, 1
  746.         mov     [ebp+FAT.fatStartScan], edi
  747.         lea     eax, [edi-1]
  748. @@:
  749.         pop     edi edx ecx
  750.         ret
  751.  
  752. .notfound:
  753.         stc
  754.         jmp     @b
  755.  
  756. write_fat_sector:
  757.         push    eax ebx ecx
  758.         mov     [ebp+FAT.fat_change], 0
  759.         mov     eax, [ebp+FAT.fat_in_cache]
  760.         cmp     eax, -1
  761.         jz      @f
  762.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  763.         mov     ecx, [ebp+FAT.NUMBER_OF_FATS]
  764. .write_next_fat:
  765.         push    eax
  766.         call    fs_write32_sys
  767.         test    eax, eax
  768.         pop     eax
  769.         jnz     @f
  770.         add     eax, [ebp+FAT.SECTORS_PER_FAT]
  771.         dec     ecx
  772.         jnz     .write_next_fat
  773. @@:
  774.         pop     ecx ebx eax
  775.         ret
  776.  
  777. get_date_for_file:
  778. ;   out in ax:
  779. ; bits 0-4 = day
  780. ; bits 5-8 = month
  781. ; bits 9-15 = count of years from 1980
  782.         mov     al, 7
  783.         call    fsReadCMOS
  784.         ror     eax, 5
  785.         mov     al, 8
  786.         call    fsReadCMOS
  787.         ror     eax, 4
  788.         mov     al, 9
  789.         call    fsReadCMOS
  790.         add     ax, 20
  791.         rol     eax, 9
  792.         ret
  793.  
  794. get_time_for_file:
  795. ;   out in ax:
  796. ; bits 0-4 = second (the low bit is lost)
  797. ; bits 5-10 = minute
  798. ; bits 11-15 = hour
  799.         mov     al, 0
  800.         call    fsReadCMOS
  801.         ror     eax, 6
  802.         mov     al, 2
  803.         call    fsReadCMOS
  804.         ror     eax, 6
  805.         mov     al, 4
  806.         call    fsReadCMOS
  807.         rol     eax, 11
  808.         ret
  809.  
  810. add_disk_free_space:
  811. ; in: ecx = cluster count (signed)
  812.         test    ecx, ecx
  813.         je      .ret
  814.         cmp     [ebp+FAT.fs_type], 32
  815.         jne     .ret
  816.         push    eax ebx
  817.         mov     eax, [ebp+FAT.ADR_FSINFO]
  818.         lea     ebx, [ebp+FAT.fsinfo_buffer]
  819.         call    fs_read32_sys
  820.         test    eax, eax
  821.         jnz     @f
  822.         cmp     dword [ebx+0x1fc], 0xaa550000   ; check sector id
  823.         jne     @f
  824.         add     [ebx+0x1e8], ecx
  825.         push    [ebp+FAT.fatStartScan]
  826.         pop     dword [ebx+0x1ec]
  827.         mov     eax, [ebp+FAT.ADR_FSINFO]
  828.         call    fs_write32_sys
  829. @@:
  830.         pop     ebx eax
  831. .ret:
  832.         ret
  833.  
  834. clear_cluster_chain:
  835. ; in: eax = first cluster
  836.         push    eax ecx edx
  837.         xor     ecx, ecx        ; cluster count
  838. @@:
  839.         cmp     eax, [ebp+FAT.LAST_CLUSTER]
  840.         ja      @f
  841.         cmp     eax, 2
  842.         jb      @f
  843.         cmp     eax, [ebp+FAT.ROOT_CLUSTER]
  844.         jz      @f
  845.         xor     edx, edx
  846.         call    set_FAT
  847.         jc      .ret
  848.         inc     ecx
  849.         mov     eax, edx
  850.         jmp     @b
  851.  
  852. @@:
  853.         call    add_disk_free_space
  854.         clc
  855. .ret:
  856.         pop     edx ecx eax
  857.         ret
  858.  
  859. update_disk:
  860.         cmp     [ebp+FAT.fat_change], 0
  861.         jz      .noChange
  862.         cmp     [ebp+FAT.fs_type], 12
  863.         jz      .fat12
  864.         call    write_fat_sector
  865.         jc      .ret
  866. .noChange:
  867.         mov     esi, [ebp+PARTITION.Disk]
  868.         call    disk_sync
  869. .ret:
  870.         ret
  871.  
  872. .fat12:
  873.         mov     esi, [ebp+FAT.fat12_unpacked_ptr]
  874.         mov     edi, [ebp+FAT.fat_cache_ptr]
  875.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  876.         and     edx, not 7
  877.         lea     edx, [esi+(edx+8)*2]
  878. @@:
  879.         mov     eax, dword [esi]
  880.         mov     ebx, dword [esi+4]
  881.         shl     ax, 4
  882.         shl     eax, 4
  883.         shl     bx, 4
  884.         shr     ebx, 4
  885.         shrd    eax, ebx, 8
  886.         shr     ebx, 8
  887.         mov     dword [edi], eax
  888.         mov     word [edi+4], bx
  889.         add     edi, 6
  890.         add     esi, 8
  891.         cmp     esi, edx
  892.         jb      @b
  893.         mov     esi, [ebp+FAT.NUMBER_OF_FATS]
  894.         mov     edx, [ebp+FAT.LAST_CLUSTER]
  895.         lea     edx, [(edx+1)*3 + 512*2-1]
  896.         shr     edx, 10
  897.         push    [ebp+FAT.FAT_START]
  898. .write_fats:
  899.         xor     eax, eax
  900.         mov     ebx, [ebp+FAT.fat_cache_ptr]
  901. .loop1:
  902.         push    eax
  903.         add     eax, [esp+4]
  904.         call    fs_write32_sys
  905.         test    eax, eax
  906.         pop     eax
  907.         jnz     @f
  908.         add     ebx, 512
  909.         inc     eax
  910.         cmp     eax, edx
  911.         jb      .loop1
  912.         pop     eax
  913.         add     eax, [ebp+FAT.SECTORS_PER_FAT]
  914.         push    eax
  915.         dec     esi
  916.         jnz     .write_fats
  917. @@:
  918.         pop     eax
  919.         mov     [ebp+FAT.fat_change], 0
  920.         jmp     .noChange
  921.  
  922. fat_lock:
  923.         lea     ecx, [ebp+FAT.Lock]
  924.         jmp     mutex_lock
  925.  
  926. fat_unlock:
  927.         lea     ecx, [ebp+FAT.Lock]
  928.         jmp     mutex_unlock
  929.  
  930. fat_get_name:
  931. ; in: edi -> FAT entry, esi -> buffer for UTF-16 name
  932. ; out: CF=1 -> no valid entry
  933.         cmp     byte [edi], 0
  934.         jz      .no
  935.         cmp     byte [edi], 0xE5
  936.         jz      .no
  937.         cmp     byte [edi+11], 0xF
  938.         jz      .longname
  939.         push    edi
  940.         xchg    esi, edi
  941.         test    byte [esi+11], 8
  942.         jnz     .label
  943.         pushd   ecx 8
  944.         pop     ecx
  945.         xor     eax, eax
  946. @@:
  947.         lodsb
  948.         stosw
  949.         loop    @b
  950.         mov     cl, 8
  951. @@:
  952.         cmp     word [edi-2], ' '
  953.         jnz     @f
  954.         sub     edi, 2
  955.         loop    @b
  956. @@:
  957.         mov     word [edi], '.'
  958.         add     edi, 2
  959.         mov     cl, 3
  960. @@:
  961.         lodsb
  962.         stosw
  963.         loop    @b
  964.         mov     cl, 3
  965. @@:
  966.         cmp     word [edi-2], ' '
  967.         jnz     @f
  968.         sub     edi, 2
  969.         loop    @b
  970.         sub     edi, 2
  971. @@:
  972.         and     word [edi], 0   ; CF=0
  973.         pop     ecx edi
  974.         ret
  975.  
  976. .label:
  977.         lea     edi, [ebp+FAT.volumeLabel]
  978.         movsd
  979.         movsd
  980.         movsd
  981.         pop     edi
  982. .no:
  983.         stc
  984.         ret
  985.  
  986. .longname:
  987.         mov     al, byte [edi]
  988.         and     eax, 0x3F
  989.         dec     eax
  990.         cmp     al, 20
  991.         jae     .no     ; ignore invalid entries
  992.         mov     word [esi+260*2], 0     ; force null-terminating for orphans
  993.         imul    eax, 13*2
  994.         test    byte [edi], 0x40
  995.         jz      @f
  996.         mov     word [esi+eax+13*2], 0
  997. @@: ; copy name (13 chars in UTF-16)
  998.         push    edi
  999.         inc     edi
  1000.         add     esi, eax
  1001.         xchg    esi, edi
  1002.         movsd
  1003.         movsd
  1004.         movsw
  1005.         add     esi, 3
  1006.         movsd
  1007.         movsd
  1008.         movsd
  1009.         add     esi, 2
  1010.         movsd
  1011.         pop     edi
  1012.         test    eax, eax
  1013.         jnz     .no ; if this is not first entry, more processing required
  1014.         ret
  1015.  
  1016. fat_find_lfn:
  1017. ;   in:
  1018. ; esi -> path in UTF-8
  1019. ; parameters in the stack
  1020. ;   out:
  1021. ; esi -> next name in the path
  1022. ; edi -> direntry
  1023. ; CF=1 -> file not found, eax = error code
  1024.         lea     eax, [esp+12]
  1025.         call    dword [eax-4]
  1026.         jc      .reterr
  1027.         sub     esp, 262*2      ; reserve place for LFN
  1028. .l1:
  1029.         push    esi
  1030.         lea     esi, [esp+4]
  1031.         call    fat_get_name
  1032.         pop     esi
  1033.         jc      .no
  1034.         push    edi esi
  1035.         lea     edi, [esp+8]
  1036. @@:
  1037.         call    utf8to16
  1038.         call    utf16toUpper
  1039.         mov     edx, eax
  1040.         mov     ax, [edi]
  1041.         call    utf16toUpper
  1042.         cmp     ax, dx
  1043.         jnz     .done
  1044.         add     edi, 2
  1045.         test    ax, ax
  1046.         jnz     @b
  1047.         dec     esi
  1048.         pop     eax edi
  1049. .found:
  1050.         add     esp, 262*2
  1051. ; if this is LFN entry, advance to true entry
  1052.         cmp     byte [edi+11], 0xF
  1053.         jnz     @f
  1054.         lea     eax, [esp+12]
  1055.         call    dword[eax-8]
  1056.         jc      .reterr
  1057. @@:
  1058.         xor     eax, eax
  1059.         ret
  1060.  
  1061. .done:
  1062.         cmp     dx, '/'
  1063.         jnz     @f
  1064.         test    ax, ax
  1065.         jnz     @f
  1066.         mov     [esp], esi
  1067. @@:
  1068.         pop     esi edi
  1069.         jz      .found
  1070. .no:
  1071.         lea     eax, [esp+262*2+12]
  1072.         call    dword[eax-8]
  1073.         jnc     .l1
  1074.         add     esp, 262*2
  1075. .reterr:
  1076.         stc
  1077.         ret
  1078.  
  1079. fat_time_to_bdfe:
  1080. ; in: eax=FAT time
  1081. ; out: eax=BDFE time
  1082.         push    ecx edx
  1083.         mov     ecx, eax
  1084.         mov     edx, eax
  1085.         shr     eax, 11
  1086.         shl     eax, 16 ; hours
  1087.         and     edx, 0x1F
  1088.         add     edx, edx
  1089.         mov     al, dl  ; seconds
  1090.         shr     ecx, 5
  1091.         and     ecx, 0x3F
  1092.         mov     ah, cl  ; minutes
  1093.         pop     edx ecx
  1094.         ret
  1095.  
  1096. fat_date_to_bdfe:
  1097.         push    ecx edx
  1098.         mov     ecx, eax
  1099.         mov     edx, eax
  1100.         shr     eax, 9
  1101.         add     ax, 1980
  1102.         shl     eax, 16 ; year
  1103.         and     edx, 0x1F
  1104.         mov     al, dl  ; day
  1105.         shr     ecx, 5
  1106.         and     ecx, 0xF
  1107.         mov     ah, cl  ; month
  1108.         pop     edx ecx
  1109.         ret
  1110.  
  1111. bdfe_to_fat_time:
  1112.         push    edx
  1113.         mov     edx, eax
  1114.         shr     eax, 16
  1115.         and     dh, 0x3F
  1116.         shl     eax, 6
  1117.         or      al, dh
  1118.         shr     dl, 1
  1119.         and     dl, 0x1F
  1120.         shl     eax, 5
  1121.         or      al, dl
  1122.         pop     edx
  1123.         ret
  1124.  
  1125. bdfe_to_fat_date:
  1126.         push    edx
  1127.         mov     edx, eax
  1128.         shr     eax, 16
  1129.         sub     ax, 1980
  1130.         and     dh, 0xF
  1131.         shl     eax, 4
  1132.         or      al, dh
  1133.         and     dl, 0x1F
  1134.         shl     eax, 5
  1135.         or      al, dl
  1136.         pop     edx
  1137.         ret
  1138.  
  1139. fat_entry_to_bdfe:
  1140. ; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
  1141.         mov     eax, [ebp-4]
  1142.         mov     [esi+4], eax    ; cp866/UNICODE name
  1143. fat_entry_to_bdfe2:
  1144.         movzx   eax, byte [edi+11]
  1145.         mov     [esi], eax      ; attributes
  1146.         movzx   eax, word [edi+14]
  1147.         call    fat_time_to_bdfe
  1148.         mov     [esi+8], eax    ; creation time
  1149.         movzx   eax, word [edi+16]
  1150.         call    fat_date_to_bdfe
  1151.         mov     [esi+12], eax   ; creation date
  1152.         and     dword [esi+16], 0       ; last access time is not supported on FAT
  1153.         movzx   eax, word [edi+18]
  1154.         call    fat_date_to_bdfe
  1155.         mov     [esi+20], eax   ; last access date
  1156.         movzx   eax, word [edi+22]
  1157.         call    fat_time_to_bdfe
  1158.         mov     [esi+24], eax   ; last write time
  1159.         movzx   eax, word [edi+24]
  1160.         call    fat_date_to_bdfe
  1161.         mov     [esi+28], eax   ; last write date
  1162.         mov     eax, [edi+28]
  1163.         mov     [esi+32], eax   ; file size (low dword)
  1164.         xor     eax, eax
  1165.         mov     [esi+36], eax   ; file size (high dword)
  1166.         test    ebp, ebp
  1167.         jz      .ret
  1168.         add     esi, 40
  1169.         push    edi esi
  1170.         mov     edi, esi
  1171.         mov     esi, ebp
  1172.         cmp     byte [ebp-4], 2
  1173.         jz      .utf16
  1174.         cmp     byte [ebp-4], 3
  1175.         jz      .utf8
  1176. @@:
  1177.         lodsw
  1178.         call    uni2ansi_char
  1179.         stosb
  1180.         test    al, al
  1181.         jnz     @b
  1182.         pop     esi edi
  1183.         add     esi, 264
  1184. .ret:
  1185.         ret
  1186.  
  1187. .utf8:
  1188.         push    ecx
  1189.         mov     ecx, 519
  1190.         call    UTF16to8_string
  1191.         pop     ecx
  1192.         jmp     @f
  1193.  
  1194. .utf16:
  1195.         lodsw
  1196.         stosw
  1197.         test    eax, eax
  1198.         jnz     .utf16
  1199. @@:
  1200.         pop     esi edi
  1201.         add     esi, 520
  1202.         ret
  1203.  
  1204. bdfe_to_fat_entry:
  1205. ; convert BDFE at edx to FAT entry at edi
  1206. ; destroys eax
  1207. ; attributes byte
  1208.         test    byte [edi+11], 8        ; volume label?
  1209.         jnz     @f
  1210.         mov     al, [edx]
  1211.         and     al, 0x27
  1212.         and     byte [edi+11], 0x10
  1213.         or      byte [edi+11], al
  1214. @@:
  1215.         mov     eax, [edx+8]
  1216.         call    bdfe_to_fat_time
  1217.         mov     [edi+14], ax            ; creation time
  1218.         mov     eax, [edx+12]
  1219.         call    bdfe_to_fat_date
  1220.         mov     [edi+16], ax            ; creation date
  1221.         mov     eax, [edx+20]
  1222.         call    bdfe_to_fat_date
  1223.         mov     [edi+18], ax            ; last access date
  1224.         mov     eax, [edx+24]
  1225.         call    bdfe_to_fat_time
  1226.         mov     [edi+22], ax            ; last write time
  1227.         mov     eax, [edx+28]
  1228.         call    bdfe_to_fat_date
  1229.         mov     [edi+24], ax            ; last write date
  1230.         ret
  1231.  
  1232. hd_find_lfn:
  1233. ; in: esi -> path string in UTF-8
  1234. ; out: CF=1 - file not found, eax=error code
  1235. ;      else CF=0 and edi->direntry, eax=sector
  1236.         push    esi edi
  1237.         push    0
  1238.         push    0
  1239.         push    fat1x_root_first
  1240.         push    fat1x_root_next
  1241.         mov     eax, [ebp+FAT.ROOT_CLUSTER]
  1242.         cmp     [ebp+FAT.fs_type], 32
  1243.         jz      .fat32
  1244. .loop:
  1245.         and     [ebp+FAT.longname_sec1], 0
  1246.         and     [ebp+FAT.longname_sec2], 0
  1247.         call    fat_find_lfn
  1248.         jc      .notfound
  1249.         cmp     byte [esi], 0
  1250.         jz      .found
  1251.         test    byte [edi+11], 10h
  1252.         jz      .notfound
  1253.         and     dword [esp+12], 0
  1254.         mov     eax, [edi+20-2]
  1255.         mov     ax, [edi+26]    ; cluster
  1256. .fat32:
  1257.         mov     [esp+8], eax
  1258.         mov     dword [esp+4], fat_notroot_first
  1259.         mov     dword [esp], fat_notroot_next
  1260.         jmp     .loop
  1261.  
  1262. .notfound:
  1263.         add     esp, 16
  1264.         pop     edi esi
  1265.         stc
  1266.         ret
  1267.  
  1268. .found:
  1269.         lea     eax, [esp+8]
  1270.         cmp     dword [eax], 0
  1271.         jz      .root
  1272.         call    fat_get_sector
  1273.         jmp     .cmn
  1274.  
  1275. .root:
  1276.         mov     eax, [eax+4]
  1277.         add     eax, [ebp+FAT.ROOT_START]
  1278. .cmn:
  1279.         add     esp, 20         ; CF=0
  1280.         pop     esi
  1281.         ret
  1282.  
  1283. ;----------------------------------------------------------------
  1284. fat_Read:
  1285.         call    fat_lock
  1286.         call    hd_find_lfn
  1287.         jc      .notFound
  1288.         test    byte [edi+11], 0x10     ; do not allow read directories
  1289.         jnz     .noaccess
  1290.         cmp     dword [ebx+8], 0
  1291.         jnz     .endOfFile
  1292.         mov     edx, [ebx+4]    ; file offset
  1293.         mov     ecx, [ebx+12]   ; size
  1294.         mov     ebx, [ebx+16]   ; buffer
  1295.         push    ebx
  1296.         push    0
  1297.         test    ecx, ecx
  1298.         jz      .done
  1299.         mov     eax, [edi+28]
  1300.         sub     eax, edx
  1301.         jb      .fileEnd
  1302.         cmp     eax, ecx
  1303.         jae     @f
  1304.         mov     ecx, eax
  1305.         mov     byte [esp], 6
  1306. @@:
  1307.         mov     eax, [edi+20-2]
  1308.         mov     ax, [edi+26]
  1309. ; now eax=cluster, ebx=buffer for data, ecx=count, edx=position
  1310.         mov     edi, [ebp+FAT.SECTORS_PER_CLUSTER]
  1311.         shl     edi, 9
  1312. @@:
  1313.         cmp     eax, 2
  1314.         jb      .fileEnd
  1315.         cmp     eax, [ebp+FAT.fatRESERVED]
  1316.         jae     .fileEnd
  1317.         sub     edx, edi
  1318.         jc      @f
  1319.         call    get_FAT
  1320.         jc      .noaccess2
  1321.         jmp     @b
  1322.  
  1323. .notFound:
  1324.         push    eax
  1325.         jmp     .ret
  1326.  
  1327. .noaccess:
  1328.         push    ERROR_ACCESS_DENIED
  1329.         jmp     .ret
  1330.  
  1331. .endOfFile:
  1332.         push    ERROR_END_OF_FILE
  1333. .ret:
  1334.         call    fat_unlock
  1335.         pop     eax
  1336.         xor     ebx, ebx
  1337.         ret
  1338.  
  1339. @@:
  1340.         mov     esi, eax
  1341.         dec     eax
  1342.         dec     eax
  1343.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1344.         add     eax, [ebp+FAT.DATA_START]
  1345.         add     edx, edi
  1346.         jz      .alignedCluster
  1347.         mov     edi, edx
  1348.         shr     edi, 9
  1349.         add     eax, edi
  1350.         and     edx, 511
  1351.         cmp     ecx, 512
  1352.         jc      .sectorPiece
  1353.         test    edx, edx
  1354.         jz      .alignedSector
  1355. .sectorPiece:
  1356.         push    eax ebx
  1357.         lea     ebx, [ebp+FAT.buffer]
  1358.         call    fs_read32_app
  1359.         test    eax, eax
  1360.         mov     eax, ebx
  1361.         pop     ebx
  1362.         jne     .noaccess3
  1363.         add     eax, edx
  1364.         push    ecx
  1365.         add     ecx, edx
  1366.         cmp     ecx, 512
  1367.         jbe     @f
  1368.         mov     ecx, 512
  1369. @@:
  1370.         sub     ecx, edx
  1371.         call    memmove
  1372.         sub     [esp], ecx
  1373.         add     ebx, ecx
  1374.         pop     ecx eax
  1375.         xor     edx, edx
  1376.         inc     edi
  1377.         inc     eax
  1378.         test    ecx, ecx
  1379.         jz      .done
  1380. .alignedSector:
  1381.         shl     edi, 9
  1382.         add     ecx, edi
  1383.         mov     edi, [ebp+FAT.SECTORS_PER_CLUSTER]
  1384.         shl     edi, 9
  1385. .alignedCluster:
  1386.         cmp     ecx, 512
  1387.         jc      .sectorPiece
  1388.         mov     edx, eax
  1389.         mov     eax, esi
  1390. @@:
  1391.         sub     ecx, edi
  1392.         jbe     .readEnd
  1393.         call    get_FAT
  1394.         jc      .noaccess4
  1395.         cmp     eax, 2
  1396.         jb      .fileEnd2
  1397.         cmp     eax, [ebp+FAT.fatRESERVED]
  1398.         jae     .fileEnd2
  1399.         inc     esi
  1400.         cmp     eax, esi
  1401.         jz      @b
  1402. .fragmentEnd:
  1403.         xchg    eax, esi
  1404.         dec     eax
  1405.         dec     eax
  1406.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1407.         add     eax, [ebp+FAT.DATA_START]
  1408.         push    ecx
  1409.         mov     ecx, eax
  1410.         mov     eax, esi
  1411.         dec     eax
  1412.         dec     eax
  1413.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1414.         add     eax, [ebp+FAT.DATA_START]
  1415.         push    eax
  1416. .readFragment:
  1417.         sub     ecx, edx
  1418.         mov     eax, edx
  1419.         xor     edx, edx
  1420.         call    fs_read64_app
  1421.         shl     ecx, 9
  1422.         add     ebx, ecx
  1423.         test    eax, eax
  1424.         pop     eax
  1425.         jnz     .noaccess3
  1426.         pop     ecx
  1427.         xor     edx, edx
  1428.         jecxz   .done
  1429.         jmp     .alignedCluster
  1430.  
  1431. .readEnd:
  1432.         add     ecx, edi
  1433.         mov     edi, ecx
  1434.         and     ecx, 511
  1435.         shr     edi, 9
  1436.         dec     eax
  1437.         dec     eax
  1438.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1439.         add     eax, [ebp+FAT.DATA_START]
  1440.         add     eax, edi
  1441.         push    ecx
  1442.         push    eax
  1443.         mov     ecx, eax
  1444.         jmp     .readFragment
  1445.  
  1446. .noaccess3:
  1447.         pop     eax
  1448. .noaccess2:
  1449.         mov     byte [esp], ERROR_DEVICE
  1450. .done:
  1451.         call    fat_unlock
  1452.         pop     eax edx
  1453.         sub     ebx, edx
  1454.         ret
  1455.  
  1456. .fileEnd:
  1457.         mov     byte [esp], ERROR_END_OF_FILE
  1458.         jmp     .done
  1459.  
  1460. .noaccess4:
  1461.         mov     byte [esp], ERROR_DEVICE
  1462.         jmp     @f
  1463.  
  1464. .fileEnd2:
  1465.         mov     byte [esp], ERROR_END_OF_FILE
  1466. @@:
  1467.         inc     esi
  1468.         xor     ecx, ecx
  1469.         jmp     .fragmentEnd
  1470.  
  1471. ;----------------------------------------------------------------
  1472. fat_ReadFolder:
  1473.         call    fat_lock
  1474.         mov     eax, [ebp+FAT.ROOT_CLUSTER]
  1475.         cmp     byte [esi], 0
  1476.         jz      .doit
  1477.         call    hd_find_lfn
  1478.         jc      .error
  1479.         test    byte [edi+11], 0x10     ; do not allow read files
  1480.         jz      .accessDenied
  1481.         mov     eax, [edi+20-2]
  1482.         mov     ax, [edi+26]    ; eax=cluster
  1483. .doit:
  1484.         sub     esp, 262*2      ; reserve space for LFN
  1485.         push    dword [ebx+8]   ; cp866/UNICODE name
  1486.         mov     edx, [ebx+16]   ; pointer to buffer
  1487. ; init header
  1488.         push    eax
  1489.         mov     edi, edx
  1490.         mov     ecx, 32/4
  1491.         xor     eax, eax
  1492.         rep stosd
  1493.         pop     eax
  1494.         mov     byte [edx], 1   ; version
  1495.         mov     esi, edi        ; esi points to BDFE
  1496.         mov     ecx, [ebx+12]   ; number of blocks to read
  1497.         mov     ebx, [ebx+4]    ; index of the first block
  1498. .new_cluster:
  1499.         mov     [ebp+FAT.cluster_tmp], eax
  1500.         test    eax, eax
  1501.         jnz     @f
  1502.         cmp     [ebp+FAT.fs_type], 32
  1503.         jz      .notfound
  1504.         mov     eax, [ebp+FAT.ROOT_START]
  1505.         push    [ebp+FAT.ROOT_SECTORS]
  1506.         push    ebx
  1507.         jmp     .new_sector
  1508.  
  1509. @@:
  1510.         dec     eax
  1511.         dec     eax
  1512.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1513.         push    [ebp+FAT.SECTORS_PER_CLUSTER]
  1514.         add     eax, [ebp+FAT.DATA_START]
  1515.         push    ebx
  1516. .new_sector:
  1517.         lea     ebx, [ebp+FAT.buffer]
  1518.         mov     edi, ebx
  1519.         push    eax
  1520.         call    fs_read32_sys
  1521.         test    eax, eax
  1522.         pop     eax
  1523.         jnz     .notfound2
  1524.         add     ebx, 512
  1525.         push    eax
  1526. .l1:
  1527.         push    esi
  1528.         lea     esi, [esp+20]
  1529.         call    fat_get_name
  1530.         pop     esi
  1531.         jc      .l2
  1532.         cmp     byte [edi+11], 0xF
  1533.         jnz     .do_bdfe
  1534.         add     edi, 0x20
  1535.         cmp     edi, ebx
  1536.         jb      .do_bdfe
  1537.         pop     eax
  1538.         inc     eax
  1539.         dec     dword [esp+4]
  1540.         jnz     @f
  1541.         mov     eax, [ebp+FAT.cluster_tmp]
  1542.         test    eax, eax
  1543.         jz      .done
  1544.         call    get_FAT
  1545.         jc      .notfound2
  1546.         cmp     eax, 2
  1547.         jb      .done
  1548.         cmp     eax, [ebp+FAT.fatRESERVED]
  1549.         jae     .done
  1550.         push    eax
  1551.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1552.         mov     [esp+8], eax
  1553.         pop     eax
  1554.         mov     [ebp+FAT.cluster_tmp], eax
  1555.         dec     eax
  1556.         dec     eax
  1557.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1558.         add     eax, [ebp+FAT.DATA_START]
  1559. @@:
  1560.         lea     ebx, [ebp+FAT.buffer]
  1561.         mov     edi, ebx
  1562.         push    eax
  1563.         call    fs_read32_sys
  1564.         test    eax, eax
  1565.         pop     eax
  1566.         jnz     .notfound2
  1567.         add     ebx, 512
  1568.         push    eax
  1569. .do_bdfe:
  1570.         inc     dword [edx+8]   ; new file found
  1571.         dec     dword [esp+4]
  1572.         jns     .l2
  1573.         dec     ecx
  1574.         js      .l2
  1575.         inc     dword [edx+4]   ; new file block copied
  1576.         push    ebp
  1577.         lea     ebp, [esp+20]
  1578.         call    fat_entry_to_bdfe
  1579.         pop     ebp
  1580. .l2:
  1581.         add     edi, 0x20
  1582.         cmp     edi, ebx
  1583.         jb      .l1
  1584.         pop     eax
  1585.         inc     eax
  1586.         dec     dword [esp+4]
  1587.         jnz     .new_sector
  1588.         mov     eax, [ebp+FAT.cluster_tmp]
  1589.         test    eax, eax
  1590.         jz      .done
  1591.         call    get_FAT
  1592.         jc      .notfound2
  1593.         cmp     eax, 2
  1594.         jb      .done
  1595.         cmp     eax, [ebp+FAT.fatRESERVED]
  1596.         jae     .done
  1597.         push    eax
  1598.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  1599.         mov     [esp+8], eax
  1600.         pop     eax
  1601.         pop     ebx
  1602.         add     esp, 4
  1603.         jmp     .new_cluster
  1604.  
  1605. .notfound2:
  1606.         add     esp, 8
  1607. .notfound:
  1608.         add     esp, 262*2+4
  1609.         push    ERROR_DEVICE
  1610.         jmp     @f
  1611.  
  1612. .done:
  1613.         add     esp, 262*2+12
  1614.         pushd   0
  1615.         dec     ecx
  1616.         js      @f
  1617.         mov     byte [esp], ERROR_END_OF_FILE
  1618. @@:
  1619.         mov     ebx, [edx+4]
  1620. .ret:
  1621.         call    fat_unlock
  1622.         pop     eax
  1623.         ret
  1624.  
  1625. .error:
  1626.         push    eax
  1627.         xor     ebx, ebx
  1628.         jmp     .ret
  1629.  
  1630. .accessDenied:
  1631.         push    ERROR_ACCESS_DENIED
  1632.         xor     ebx, ebx
  1633.         jmp     .ret
  1634.  
  1635. fat1x_root_next:
  1636.         push    ecx
  1637.         lea     ecx, [ebp+FAT.buffer+0x200-0x20]
  1638.         cmp     edi, ecx
  1639.         jae     fat1x_root_next_sector
  1640.         add     edi, 0x20
  1641. @@:
  1642.         pop     ecx
  1643.         ret
  1644.  
  1645. fat1x_root_next_write:
  1646.         push    ecx
  1647.         lea     ecx, [ebp+FAT.buffer+0x200]
  1648.         cmp     edi, ecx
  1649.         jc      @b
  1650.         call    fat1x_root_end_write
  1651. fat1x_root_next_sector:
  1652.         push    [ebp+FAT.longname_sec2]
  1653.         pop     [ebp+FAT.longname_sec1]
  1654.         mov     ecx, [eax+4]
  1655.         push    ecx
  1656.         add     ecx, [ebp+FAT.ROOT_START]
  1657.         mov     [ebp+FAT.longname_sec2], ecx
  1658.         pop     ecx
  1659.         inc     ecx
  1660.         mov     [eax+4], ecx
  1661.         cmp     ecx, [ebp+FAT.ROOT_SECTORS]
  1662.         jnc     fat_notroot_next_err
  1663.         pop     ecx
  1664. fat1x_root_first:
  1665.         mov     eax, [eax+4]
  1666.         add     eax, [ebp+FAT.ROOT_START]
  1667.         push    ebx
  1668.         lea     edi, [ebp+FAT.buffer]
  1669.         mov     ebx, edi
  1670.         call    fs_read32_sys
  1671.         pop     ebx
  1672.         test    eax, eax
  1673.         jz      @f
  1674.         movi    eax, ERROR_DEVICE
  1675.         stc
  1676. @@:
  1677.         ret
  1678.  
  1679. fat1x_root_begin_write:
  1680.         push    edi eax
  1681.         call    fat1x_root_first
  1682.         pop     eax edi
  1683.         ret
  1684.  
  1685. fat1x_root_end_write:
  1686.         pusha
  1687.         mov     eax, [eax+4]
  1688.         add     eax, [ebp+FAT.ROOT_START]
  1689.         lea     ebx, [ebp+FAT.buffer]
  1690.         call    fs_write32_sys
  1691.         popa
  1692.         ret
  1693.  
  1694. fat_notroot_next:
  1695.         push    ecx
  1696.         lea     ecx, [ebp+FAT.buffer+0x200-0x20]
  1697.         cmp     edi, ecx
  1698.         jae     fat_notroot_next_sector
  1699.         add     edi, 0x20
  1700. @@:
  1701.         pop     ecx
  1702.         ret
  1703.  
  1704. fat_notroot_next_write:
  1705.         push    ecx
  1706.         lea     ecx, [ebp+FAT.buffer+0x200]
  1707.         cmp     edi, ecx
  1708.         jc      @b
  1709.         push    eax
  1710.         call    fat_notroot_end_write
  1711.         pop     eax
  1712. fat_notroot_next_sector:
  1713.         push    [ebp+FAT.longname_sec2]
  1714.         pop     [ebp+FAT.longname_sec1]
  1715.         push    eax
  1716.         call    fat_get_sector
  1717.         mov     [ebp+FAT.longname_sec2], eax
  1718.         pop     eax
  1719.         mov     ecx, [eax+4]
  1720.         inc     ecx
  1721.         cmp     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1722.         jae     fat_notroot_next_cluster
  1723.         mov     [eax+4], ecx
  1724.         jmp     @f
  1725.  
  1726. fat_notroot_next_err:
  1727.         pop     ecx
  1728.         movi    eax, ERROR_FILE_NOT_FOUND
  1729. fat1x_root_extend_dir:
  1730.         stc
  1731.         ret
  1732.  
  1733. fat_notroot_next_cluster:
  1734.         push    eax
  1735.         mov     eax, [eax]
  1736.         call    get_FAT
  1737.         mov     ecx, eax
  1738.         pop     eax
  1739.         jc      fat_notroot_first.deverr
  1740.         cmp     ecx, 2
  1741.         jb      fat_notroot_next_err
  1742.         cmp     ecx, [ebp+FAT.fatRESERVED]
  1743.         jae     fat_notroot_next_err
  1744.         mov     [eax], ecx
  1745.         and     dword [eax+4], 0
  1746. @@:
  1747.         pop     ecx
  1748. fat_notroot_first:
  1749.         call    fat_get_sector
  1750.         push    ebx
  1751.         lea     edi, [ebp+FAT.buffer]
  1752.         mov     ebx, edi
  1753.         call    fs_read32_sys
  1754.         pop     ebx
  1755.         test    eax, eax
  1756.         jz      .ret ; CF=0
  1757.         push    ecx
  1758. .deverr:
  1759.         pop     ecx
  1760.         mov     eax, ERROR_DEVICE
  1761.         stc
  1762. .ret:
  1763.         ret
  1764.  
  1765. fat_notroot_begin_write:
  1766.         push    eax edi
  1767.         call    fat_notroot_first
  1768.         pop     edi eax
  1769.         ret
  1770.  
  1771. fat_notroot_end_write:
  1772.         call    fat_get_sector
  1773.         push    ebx
  1774.         lea     ebx, [ebp+FAT.buffer]
  1775.         call    fs_write32_sys
  1776.         pop     ebx
  1777.         ret
  1778.  
  1779. fat_notroot_extend_dir.writeerr:
  1780.         pop     edx
  1781. @@:
  1782.         pop     eax
  1783.         ret
  1784.  
  1785. fat_notroot_extend_dir:
  1786.         push    eax
  1787.         call    get_free_FAT
  1788.         jc      @b
  1789.         push    edx
  1790.         mov     edx, [ebp+FAT.fatEND]
  1791.         call    set_FAT
  1792.         jc      .writeerr
  1793.         mov     edx, eax
  1794.         mov     eax, [esp+4]
  1795.         mov     eax, [eax]
  1796.         push    edx
  1797.         call    set_FAT
  1798.         pop     edx
  1799.         jc      .writeerr
  1800.         push    ecx
  1801.         or      ecx, -1
  1802.         call    add_disk_free_space
  1803.         mov     ecx, 512/4
  1804.         lea     edi, [ebp+FAT.buffer]
  1805.         push    edi
  1806.         xor     eax, eax
  1807.         rep stosd
  1808.         pop     edi
  1809.         pop     ecx
  1810.         mov     eax, [esp+4]
  1811.         mov     [eax], edx
  1812.         and     dword [eax+4], 0
  1813.         pop     edx
  1814.         mov     eax, [eax]
  1815.         dec     eax
  1816.         dec     eax
  1817.         push    ebx ecx
  1818.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1819.         imul    eax, ecx
  1820.         add     eax, [ebp+FAT.DATA_START]
  1821.         mov     ebx, edi
  1822. @@:
  1823.         push    eax
  1824.         call    fs_write32_sys
  1825.         pop     eax
  1826.         inc     eax
  1827.         loop    @b
  1828.         pop     ecx ebx eax
  1829.         clc
  1830.         ret
  1831.  
  1832. fat_get_sector:
  1833.         push    ecx
  1834.         mov     ecx, [eax]
  1835.         dec     ecx
  1836.         dec     ecx
  1837.         imul    ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  1838.         add     ecx, [ebp+FAT.DATA_START]
  1839.         add     ecx, [eax+4]
  1840.         mov     eax, ecx
  1841.         pop     ecx
  1842.         ret
  1843.  
  1844. ;----------------------------------------------------------------
  1845. fat_CreateFolder:
  1846.         mov     [ebp+FAT.createOption], 0
  1847.         jmp     @f
  1848.  
  1849. fat_CreateFile:
  1850.         mov     [ebp+FAT.createOption], 1
  1851. @@:
  1852.         call    fat_lock
  1853.         mov     ecx, [ebx+12]
  1854.         mov     edx, [ebx+16]
  1855. .rename:
  1856.         pushad
  1857.         xor     edi, edi
  1858.         push    esi
  1859. @@:
  1860.         lodsb
  1861.         test    al, al
  1862.         jz      @f
  1863.         cmp     al, '/'
  1864.         jnz     @b
  1865.         lea     edi, [esi-1]
  1866.         jmp     @b
  1867.  
  1868. @@:
  1869.         pop     esi
  1870.         test    edi, edi
  1871.         jnz     .noroot
  1872.         mov     edx, [ebp+FAT.ROOT_CLUSTER]
  1873.         cmp     [ebp+FAT.fs_type], 32
  1874.         jz      .pushnotroot
  1875.         xor     edx, edx
  1876.         push    edx
  1877.         push    fat1x_root_extend_dir
  1878.         push    fat1x_root_end_write
  1879.         push    fat1x_root_next_write
  1880.         push    fat1x_root_begin_write
  1881.         push    edx
  1882.         push    edx
  1883.         push    fat1x_root_first
  1884.         push    fat1x_root_next
  1885.         jmp     .common1
  1886.  
  1887. .retNotFound:
  1888.         movi    eax, ERROR_FILE_NOT_FOUND
  1889.         jmp     .ret1
  1890.  
  1891. .noAccess:
  1892.         movi    eax, ERROR_ACCESS_DENIED
  1893. .ret1:
  1894.         mov     [esp+28], eax
  1895.         call    fat_unlock
  1896.         popad
  1897.         xor     ebx, ebx
  1898.         ret
  1899.  
  1900. .full:
  1901.         movi    eax, ERROR_DISK_FULL
  1902.         jmp     .ret1
  1903.  
  1904. .noroot:
  1905.         cmp     byte [edi+1], 0
  1906.         jz      .noAccess
  1907. ; check existence
  1908.         mov     byte [edi], 0
  1909.         push    edi
  1910.         call    hd_find_lfn
  1911.         pop     esi
  1912.         mov     byte [esi], '/'
  1913.         jc      .retNotFound
  1914.         inc     esi
  1915.         test    byte [edi+11], 0x10
  1916.         jz      .noAccess   ; file
  1917.         mov     edx, [edi+20-2]
  1918.         mov     dx, [edi+26]
  1919.         movi    eax, ERROR_FS_FAIL
  1920.         cmp     edx, 2
  1921.         jb      .ret1
  1922. .pushnotroot:
  1923.         push    edx
  1924.         push    fat_notroot_extend_dir
  1925.         push    fat_notroot_end_write
  1926.         push    fat_notroot_next_write
  1927.         push    fat_notroot_begin_write
  1928.         push    0
  1929.         push    edx
  1930.         push    fat_notroot_first
  1931.         push    fat_notroot_next
  1932. .common1:
  1933.         call    fat_find_lfn
  1934.         jc      .notfound
  1935.         test    byte [edi+11], 10h
  1936.         jz      .exists_file
  1937. ; found directory
  1938.         add     esp, 36
  1939.         call    fat_unlock
  1940.         popad
  1941.         xor     eax, eax
  1942.         cmp     [ebp+FAT.createOption], 0
  1943.         jz      @f
  1944.         mov     al, ERROR_ACCESS_DENIED
  1945. @@:
  1946.         xor     ebx, ebx
  1947.         ret
  1948.  
  1949. .exists_file:
  1950.         cmp     [ebp+FAT.createOption], 1
  1951.         jz      @f
  1952.         add     esp, 36
  1953.         jmp     .noAccess
  1954.  
  1955. @@: ; delete FAT chain
  1956.         push    edi
  1957.         xor     eax, eax
  1958.         mov     dword [edi+28], eax     ; zero size
  1959.         xor     ecx, ecx
  1960.         mov     eax, [edi+20-2]
  1961.         mov     ax, [edi+26]
  1962.         mov     word [edi+20], cx
  1963.         mov     word [edi+26], cx
  1964.         test    eax, eax
  1965.         jz      .done1
  1966. @@:
  1967.         cmp     eax, [ebp+FAT.fatRESERVED]
  1968.         jae     .done1
  1969.         xor     edx, edx
  1970.         call    set_FAT
  1971.         mov     eax, edx
  1972.         jc      .done1
  1973.         inc     ecx
  1974.         jmp     @b
  1975.  
  1976. .short_name_found:
  1977.         pop     ecx edi esi
  1978.         call    fat_next_short_name
  1979.         jnc     .test_short_name_loop
  1980. .disk_full:
  1981.         add     esp, 12+36
  1982.         jmp     .full
  1983.  
  1984. .notfound:  ; generate short name
  1985.         call    fat_name_is_legal
  1986.         jc      @f
  1987.         add     esp, 36
  1988.         jmp     .retNotFound
  1989.  
  1990. @@:
  1991.         sub     esp, 12
  1992.         mov     edi, esp
  1993.         call    fat_gen_short_name
  1994. .test_short_name_loop:
  1995.         push    esi edi ecx
  1996.         mov     esi, edi
  1997.         lea     eax, [esp+12+12+8]
  1998.         mov     edx, [eax+24]
  1999.         mov     [eax], edx
  2000.         and     dword [eax+4], 0
  2001.         call    dword [eax-4]
  2002.         jc      .found
  2003. .test_short_name_entry:
  2004.         cmp     byte [edi+11], 0xF
  2005.         jz      .test_short_name_cont
  2006.         mov     ecx, 11
  2007.         push    esi edi
  2008.         repz cmpsb
  2009.         pop     edi esi
  2010.         jz      .short_name_found
  2011. .test_short_name_cont:
  2012.         lea     eax, [esp+12+12+8]
  2013.         call    dword [eax-8]
  2014.         jnc     .test_short_name_entry
  2015. .found:
  2016.         pop     ecx edi esi
  2017. ; now find space in directory
  2018. ; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
  2019.         mov     al, '~'
  2020.         push    ecx edi
  2021.         mov     ecx, 8
  2022.         repnz scasb
  2023.         movi    eax, 1     ; 1 entry
  2024.         jnz     .notilde
  2025. ; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
  2026.         xor     ecx, ecx
  2027.         push    esi
  2028. @@:
  2029.         call    utf8to16
  2030.         inc     ecx
  2031.         test    ax, ax
  2032.         jnz     @b
  2033.         pop     esi
  2034.         mov     eax, ecx
  2035.         add     eax, 12+13-1
  2036.         mov     ecx, 13
  2037.         cdq
  2038.         div     ecx
  2039. .notilde:
  2040.         push    -1
  2041.         push    -1
  2042.         push    -1
  2043. ; find <eax> successive entries in directory
  2044.         xor     ecx, ecx
  2045.         push    eax
  2046.         lea     eax, [esp+16+8+12+8]
  2047.         mov     edx, [eax+24]
  2048.         mov     [eax], edx
  2049.         and     dword [eax+4], 0
  2050.         call    dword [eax-4]
  2051.         pop     eax
  2052.         jnc     .scan_dir
  2053. .fsfrfe3:
  2054.         add     esp, 12+8+12+36
  2055.         movi    eax, ERROR_DEVICE
  2056.         jmp     .ret1
  2057.  
  2058. .scan_dir:
  2059.         cmp     byte [edi], 0
  2060.         jz      .free
  2061.         cmp     byte [edi], 0xE5
  2062.         jz      .free
  2063.         xor     ecx, ecx
  2064. .scan_cont:
  2065.         push    eax
  2066.         lea     eax, [esp+16+8+12+8]
  2067.         call    dword [eax-8]
  2068.         mov     edx, eax
  2069.         pop     eax
  2070.         jnc     .scan_dir
  2071.         cmp     edx, ERROR_DEVICE
  2072.         jz      .fsfrfe3
  2073.         push    eax
  2074.         lea     eax, [esp+16+8+12+8]
  2075.         call    dword [eax+20]          ; extend directory
  2076.         pop     eax
  2077.         jnc     .scan_dir
  2078.         add     esp, 12+8+12+36
  2079.         jmp     .full
  2080.  
  2081. .free:
  2082.         test    ecx, ecx
  2083.         jnz     @f
  2084.         mov     [esp], edi
  2085.         mov     ecx, [esp+12+8+12+8]
  2086.         mov     [esp+4], ecx
  2087.         mov     ecx, [esp+12+8+12+12]
  2088.         mov     [esp+8], ecx
  2089.         xor     ecx, ecx
  2090. @@:
  2091.         inc     ecx
  2092.         cmp     ecx, eax
  2093.         jb      .scan_cont
  2094. ; found!
  2095.         push    esi ecx
  2096. ; If creating a directory, allocate one data cluster or fail immediately if this is impossible.
  2097. ; This prevents from creating an invalid directory entry on a full disk.
  2098.         cmp     [ebp+FAT.createOption], 0
  2099.         jnz     .notFolder
  2100.         call    get_free_FAT
  2101.         jnc     @f
  2102.         add     esp, 8+12+8
  2103.         jmp     .disk_full
  2104.  
  2105. @@:
  2106.         mov     [esp+8+12+8+12+36+20], eax  ; store the cluster somewhere
  2107. .notFolder: ; calculate name checksum
  2108.         mov     esi, [esp+8+12]
  2109.         mov     ecx, 11
  2110.         xor     eax, eax
  2111. @@:
  2112.         ror     al, 1
  2113.         add     al, [esi]
  2114.         inc     esi
  2115.         loop    @b
  2116.         pop     ecx esi edi
  2117.         pop     dword [esp+8+12+12]
  2118.         pop     dword [esp+8+12+12]
  2119. ; edi points to first entry in free chunk
  2120.         dec     ecx
  2121.         jz      .nolfn
  2122.         push    esi eax
  2123.         lea     eax, [esp+8+8+12+8]
  2124.         call    dword [eax+8]   ; begin write
  2125.         mov     al, 40h
  2126. .writelfn:
  2127.         or      al, cl
  2128.         stosb
  2129.         mov     esi, [esp+4]
  2130.         push    ecx
  2131.         dec     ecx
  2132.         jz      @f
  2133.         imul    ecx, 13
  2134. .scroll:
  2135.         call    utf8to16
  2136.         loop    .scroll
  2137. @@:
  2138.         mov     cl, 5
  2139.         call    fat_read_symbols
  2140.         mov     ax, 0xF
  2141.         stosw
  2142.         mov     al, [esp+4]
  2143.         stosb
  2144.         mov     cl, 6
  2145.         call    fat_read_symbols
  2146.         xor     eax, eax
  2147.         stosw
  2148.         mov     cl, 2
  2149.         call    fat_read_symbols
  2150.         pop     ecx
  2151.         lea     eax, [esp+8+8+12+8]
  2152.         call    dword [eax+12]  ; next write
  2153.         xor     eax, eax
  2154.         loop    .writelfn
  2155.         pop     eax esi
  2156. .nolfn:
  2157.         pop     esi
  2158.         add     esp, 16
  2159.         mov     ecx, 11
  2160.         rep movsb
  2161.         cmp     [ebp+FAT.createOption], 2
  2162.         jz      .copy
  2163.         mov     word [edi], 20h         ; attributes
  2164.         sub     edi, 11
  2165.         mov     byte [edi+13], 0        ; tenths of a second at file creation time
  2166.         call    get_time_for_file
  2167.         mov     [edi+14], ax            ; creation time
  2168.         mov     [edi+22], ax            ; last write time
  2169.         call    get_date_for_file
  2170.         mov     [edi+16], ax            ; creation date
  2171.         mov     [edi+24], ax            ; last write date
  2172.         mov     [edi+18], ax            ; last access date
  2173.         mov     word [edi+20], cx       ; high word of cluster
  2174.         mov     word [edi+26], cx       ; low word of cluster - to be filled
  2175.         mov     dword [edi+28], ecx     ; file size - to be filled
  2176.         cmp     [ebp+FAT.createOption], 0
  2177.         jnz     .doit
  2178. ; create directory
  2179.         mov     byte [edi+11], 10h      ; attributes: folder
  2180.         mov     esi, edi
  2181.         mov     eax, [esp+36+20] ; extract saved cluster
  2182.         mov     [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space!
  2183.         push    ecx
  2184.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2185.         shl     ecx, 9
  2186.         push    ecx
  2187.         push    edi
  2188.         jmp     .doit2
  2189.  
  2190. .copy:
  2191.         lea     esi, [esp+72+11]
  2192.         mov     cl, 21
  2193.         rep movsb
  2194.         sub     edi, 32
  2195.         jmp     .doit
  2196.  
  2197. .done1:
  2198.         pop     edi
  2199.         call    get_time_for_file
  2200.         mov     [edi+22], ax
  2201.         call    get_date_for_file
  2202.         mov     [edi+24], ax
  2203.         mov     [edi+18], ax
  2204.         or      byte [edi+11], 20h      ; set 'archive' attribute
  2205. .doit:
  2206.         mov     esi, [esp+36+20]
  2207.         lea     eax, [esp+8]
  2208.         call    dword [eax+16]  ; flush directory
  2209.         push    ecx
  2210.         mov     ecx, [esp+4+36+24]
  2211.         xor     eax, eax
  2212.         test    ecx, ecx
  2213.         jz      .done
  2214.         push    ecx edi
  2215.         call    get_free_FAT
  2216.         jc      .diskfull
  2217. .doit2:
  2218.         push    eax
  2219.         mov     [edi+26], ax
  2220.         shr     eax, 16
  2221.         mov     [edi+20], ax
  2222.         lea     eax, [esp+16+8]
  2223.         call    dword [eax+16]  ; flush directory
  2224.         pop     eax
  2225.         mov     edx, [ebp+FAT.fatEND]
  2226.         call    set_FAT
  2227. .write_cluster:
  2228.         push    eax
  2229.         dec     eax
  2230.         dec     eax
  2231.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2232.         add     eax, [ebp+FAT.DATA_START]
  2233.         push    [ebp+FAT.SECTORS_PER_CLUSTER]
  2234. .write_sector:
  2235.         cmp     [ebp+FAT.createOption], 0
  2236.         jz      .writedir
  2237.         mov     ecx, 512
  2238.         cmp     dword [esp+12], ecx
  2239.         jb      .writeshort
  2240. ; we can write directly from given buffer
  2241.         mov     ebx, esi
  2242.         add     esi, ecx
  2243.         jmp     .writecommon
  2244.  
  2245. .writedir:
  2246.         push    512
  2247.         lea     edi, [ebp+FAT.buffer]
  2248.         mov     ebx, edi
  2249.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2250.         shl     ecx, 9
  2251.         cmp     ecx, [esp+16]
  2252.         jnz     .writedircont
  2253.         dec     dword [esp+20]
  2254.         push    esi
  2255.         mov     ecx, 32/4
  2256.         rep movsd
  2257.         pop     esi
  2258.         mov     dword [edi-32], '.   '
  2259.         mov     dword [edi-32+4], '    '
  2260.         mov     dword [edi-32+8], '    '
  2261.         mov     byte [edi-32+11], 10h
  2262.         push    esi
  2263.         mov     ecx, 32/4
  2264.         rep movsd
  2265.         pop     esi
  2266.         mov     dword [edi-32], '..  '
  2267.         mov     dword [edi-32+4], '    '
  2268.         mov     dword [edi-32+8], '    '
  2269.         mov     byte [edi-32+11], 10h
  2270.         mov     ecx, [esp+20+36]
  2271.         cmp     ecx, [ebp+FAT.ROOT_CLUSTER]
  2272.         jnz     @f
  2273.         xor     ecx, ecx
  2274. @@:
  2275.         mov     word [edi-32+26], cx
  2276.         shr     ecx, 16
  2277.         mov     [edi-32+20], cx
  2278.         jmp     .writedircont
  2279.  
  2280. .writeshort:
  2281.         mov     ecx, [esp+12]
  2282.         push    ecx
  2283.         lea     edi, [ebp+FAT.buffer]
  2284.         mov     ebx, edi
  2285.         rep movsb
  2286. .writedircont:
  2287.         lea     ecx, [ebp+FAT.buffer+0x200]
  2288.         sub     ecx, edi
  2289.         push    eax
  2290.         xor     eax, eax
  2291.         rep stosb
  2292.         pop     eax
  2293.         pop     ecx
  2294. .writecommon:
  2295.         push    eax
  2296.         call    fs_write32_app
  2297.         test    eax, eax
  2298.         pop     eax
  2299.         jnz     .writeerr
  2300.         inc     eax
  2301.         sub     dword [esp+12], ecx
  2302.         jz      .writedone
  2303.         dec     dword [esp]
  2304.         jnz     .write_sector
  2305.         pop     eax
  2306. ; allocate new cluster
  2307.         pop     eax
  2308.         mov     ecx, eax
  2309.         call    get_free_FAT
  2310.         jc      .diskfull
  2311.         mov     edx, [ebp+FAT.fatEND]
  2312.         call    set_FAT
  2313.         xchg    eax, ecx
  2314.         mov     edx, ecx
  2315.         call    set_FAT
  2316.         xchg    eax, ecx
  2317.         jmp     .write_cluster
  2318.  
  2319. .diskfull:
  2320.         mov     eax, ERROR_DISK_FULL
  2321.         jmp     .ret
  2322.  
  2323. .writeerr:
  2324.         pop     eax eax
  2325.         sub     esi, ecx
  2326.         mov     eax, ERROR_DEVICE
  2327.         jmp     .ret
  2328.  
  2329. .writedone:
  2330.         pop     eax eax
  2331.         xor     eax, eax
  2332. .ret:
  2333.         pop     edi ecx
  2334.         inc     ecx
  2335. .done:
  2336.         sub     esi, [esp+4+36+20]
  2337.         mov     [esp+4+36+28], eax
  2338.         mov     [esp+4+36+16], esi
  2339.         jecxz   @f
  2340.         lea     eax, [esp+12]
  2341.         call    dword [eax+8]
  2342.         mov     [edi+28], esi
  2343.         call    dword [eax+16]
  2344. @@:
  2345.         lea     eax, [esi+511]
  2346.         shr     eax, 9
  2347.         mov     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2348.         lea     eax, [eax+ecx-1]
  2349.         xor     edx, edx
  2350.         div     ecx
  2351.         pop     ecx
  2352.         sub     ecx, eax
  2353.         call    add_disk_free_space
  2354.         add     esp, 36
  2355.         cmp     [ebp+FAT.createOption], 2
  2356.         jz      @f
  2357.         call    update_disk
  2358.         call    fat_unlock
  2359. @@:
  2360.         popad
  2361.         ret
  2362.  
  2363. @@:
  2364.         or      eax, -1
  2365.         rep stosw
  2366.         ret
  2367.  
  2368. fat_read_symbols:
  2369.         test    esi, esi
  2370.         jz      @b
  2371.         call    utf8to16
  2372.         stosw
  2373.         test    ax, ax
  2374.         jnz     @f
  2375.         xor     esi, esi
  2376. @@:
  2377.         loop    fat_read_symbols
  2378.         ret
  2379.  
  2380. ;----------------------------------------------------------------
  2381. fat_Write:
  2382.         call    fat_lock
  2383.         call    hd_find_lfn
  2384.         jc      .error
  2385.         cmp     dword [ebx+8], 0
  2386.         jnz     .eof    ; FAT does not support files larger than 4GB
  2387.         mov     ecx, [ebx+12]
  2388.         mov     edx, [ebx+16]
  2389.         mov     ebx, [ebx+4]
  2390. ; now edi points to direntry, ebx=start byte to write,
  2391. ; ecx=number of bytes to write, edx=data pointer
  2392. ; extend file if needed
  2393.         add     ecx, ebx
  2394.         jc      .eof    ; FAT does not support files larger than 4GB
  2395.         push    edx
  2396.         push    eax     ; save directory sector
  2397.         push    0       ; return value=0
  2398.         call    get_time_for_file
  2399.         mov     [edi+22], ax            ; last write time
  2400.         call    get_date_for_file
  2401.         mov     [edi+24], ax            ; last write date
  2402.         mov     [edi+18], ax            ; last access date
  2403.         push    dword [edi+28]          ; save current file size
  2404.         cmp     ecx, [edi+28]
  2405.         jbe     .length_ok
  2406.         cmp     ecx, ebx
  2407.         jz      .length_ok
  2408.         call    hd_extend_file
  2409.         jnc     .length_ok
  2410.         mov     [esp+4], eax
  2411. ; hd_extend_file can return three error codes: FAT table error, device error or disk full.
  2412. ; First two cases are fatal errors, in third case we may write some data
  2413.         cmp     al, ERROR_DISK_FULL
  2414.         jnz     @f
  2415. ; correct number of bytes to write
  2416.         mov     ecx, [edi+28]
  2417.         cmp     ecx, ebx
  2418.         ja      .length_ok
  2419.         push    0
  2420. .ret:
  2421.         pop     eax
  2422.         sub     edx, [esp+12]
  2423.         mov     ebx, edx        ; ebx=number of written bytes
  2424.         call    update_disk
  2425.         test    eax, eax
  2426.         jz      @f
  2427.         mov     byte [esp+4], ERROR_DEVICE
  2428. @@:
  2429.         pop     eax eax ecx edx
  2430. .error:
  2431.         push    eax
  2432. @@:
  2433.         call    fat_unlock
  2434.         pop     eax
  2435.         ret
  2436.  
  2437. .eof:
  2438.         push    ERROR_END_OF_FILE
  2439.         xor     ebx, ebx
  2440.         jmp     @b
  2441.  
  2442. .device_err2:
  2443.         pop     ecx
  2444. .device_err:
  2445.         mov     byte [esp+8], ERROR_DEVICE
  2446.         jmp     .ret
  2447.  
  2448. .fat_err:
  2449.         mov     byte [esp+8], ERROR_FS_FAIL
  2450.         jmp     .ret
  2451.  
  2452. .length_ok:
  2453.         mov     esi, [edi+28]
  2454.         mov     eax, [edi+20-2]
  2455.         mov     ax, [edi+26]
  2456.         mov     edi, eax        ; edi=current cluster
  2457.         push    0               ; current sector in cluster
  2458. ; save directory
  2459.         mov     eax, [esp+12]
  2460.         push    ebx
  2461.         lea     ebx, [ebp+FAT.buffer]
  2462.         call    fs_write32_sys
  2463.         pop     ebx
  2464.         test    eax, eax
  2465.         jnz     .device_err
  2466. ; now ebx=start pos, ecx=end pos, both lie inside file
  2467.         sub     ecx, ebx
  2468.         jz      .ret
  2469. .write_loop:
  2470. ; skip unmodified sectors
  2471.         cmp     dword [esp+4], 0x200
  2472.         jb      .modify
  2473.         sub     ebx, 0x200
  2474.         jae     .skip
  2475.         add     ebx, 0x200
  2476. .modify:
  2477. ; get length of data in current sector
  2478.         push    ecx
  2479.         sub     ebx, 0x200
  2480.         jb      .hasdata
  2481.         neg     ebx
  2482.         xor     ecx, ecx
  2483.         jmp     @f
  2484. .hasdata:
  2485.         neg     ebx
  2486.         cmp     ecx, ebx
  2487.         jbe     @f
  2488.         mov     ecx, ebx
  2489. @@:
  2490. ; get current sector number
  2491.         mov     eax, edi
  2492.         dec     eax
  2493.         dec     eax
  2494.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2495.         add     eax, [ebp+FAT.DATA_START]
  2496.         add     eax, [esp+4]
  2497. ; load sector if needed
  2498.         cmp     dword [esp+8], 0        ; we don't need to read uninitialized data
  2499.         jz      .noread
  2500.         cmp     ecx, 0x200      ; we don't need to read sector if it is fully rewritten
  2501.         jz      .noread
  2502.         cmp     ecx, esi        ; (same for the last sector)
  2503.         jz      .noread
  2504.         push    eax ebx
  2505.         lea     ebx, [ebp+FAT.buffer]
  2506.         call    fs_read32_app
  2507.         test    eax, eax
  2508.         pop     ebx eax
  2509.         jnz     .device_err2
  2510. .noread:
  2511. ; zero uninitialized data if file was extended (because hd_extend_file does not this)
  2512.         push    eax ecx edi
  2513.         xor     eax, eax
  2514.         mov     ecx, 0x200
  2515.         sub     ecx, [esp+8+12]
  2516.         jbe     @f
  2517.         lea     edi, [ebp+FAT.buffer]
  2518.         add     edi, [esp+8+12]
  2519.         rep stosb
  2520. @@:
  2521. ; zero uninitialized data in the last sector
  2522.         mov     ecx, 0x200
  2523.         sub     ecx, esi
  2524.         jbe     @f
  2525.         lea     edi, [ebp+FAT.buffer+esi]
  2526.         rep stosb
  2527. @@:
  2528.         pop     edi ecx
  2529. ; copy new data
  2530.         mov     eax, edx
  2531.         neg     ebx
  2532.         jecxz   @f
  2533.         lea     ebx, [ebp+FAT.buffer+0x200+ebx]
  2534.         call    memmove
  2535.         xor     ebx, ebx
  2536. @@:
  2537.         pop     eax
  2538. ; save sector
  2539.         push    ebx
  2540.         lea     ebx, [ebp+FAT.buffer]
  2541.         call    fs_write32_app
  2542.         pop     ebx
  2543.         test    eax, eax
  2544.         jnz     .device_err2
  2545.         add     edx, ecx
  2546.         sub     [esp], ecx
  2547.         pop     ecx
  2548.         jz      .ret
  2549. .skip:
  2550. ; next sector
  2551.         pop     eax
  2552.         inc     eax
  2553.         push    eax
  2554.         cmp     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2555.         jb      @f
  2556.         and     dword [esp], 0
  2557.         mov     eax, edi
  2558.         call    get_FAT
  2559.         mov     edi, eax
  2560.         jc      .device_err
  2561.         cmp     edi, 2
  2562.         jb      .fat_err
  2563.         cmp     edi, [ebp+FAT.fatRESERVED]
  2564.         jae     .fat_err
  2565. @@:
  2566.         sub     esi, 0x200
  2567.         jae     @f
  2568.         xor     esi, esi
  2569. @@:
  2570.         sub     dword [esp+4], 0x200
  2571.         jae     @f
  2572.         and     dword [esp+4], 0
  2573. @@:
  2574.         jmp     .write_loop
  2575.  
  2576. hd_extend_file.zero_size:
  2577.         xor     eax, eax
  2578.         jmp     hd_extend_file.start_extend
  2579.  
  2580. ; extends file on hd to given size (new data area is undefined)
  2581. ; in: edi->direntry, ecx=new size
  2582. ; out: CF=0 => OK, eax=0
  2583. ;      CF=1 => error, eax=code (ERROR_FS_FAIL or ERROR_DISK_FULL or ERROR_DEVICE)
  2584. hd_extend_file:
  2585.         push    esi
  2586.         mov     esi, [ebp+FAT.SECTORS_PER_CLUSTER]
  2587.         imul    esi, [ebp+FAT.BYTES_PER_SECTOR]
  2588.         push    ecx
  2589. ; find the last cluster of file
  2590.         mov     eax, [edi+20-2]
  2591.         mov     ax, [edi+26]
  2592.         mov     ecx, [edi+28]
  2593.         jecxz   .zero_size
  2594. .last_loop:
  2595.         sub     ecx, esi
  2596.         jbe     .last_found
  2597.         call    get_FAT
  2598.         jnc     @f
  2599. .device_err:
  2600.         pop     ecx
  2601. .device_err2:
  2602.         pop     esi
  2603.         push    ERROR_DEVICE
  2604. .ret_err:
  2605.         pop     eax
  2606.         stc
  2607.         ret
  2608. @@:
  2609.         cmp     eax, 2
  2610.         jb      .fat_err
  2611.         cmp     eax, [ebp+FAT.fatRESERVED]
  2612.         jb      .last_loop
  2613. .fat_err:
  2614.         pop     ecx esi
  2615.         push    ERROR_FS_FAIL
  2616.         jmp     .ret_err
  2617. .last_found:
  2618.         push    eax
  2619.         call    get_FAT
  2620.         jnc     @f
  2621.         pop     eax
  2622.         jmp     .device_err
  2623. @@:
  2624.         cmp     eax, [ebp+FAT.fatRESERVED]
  2625.         pop     eax
  2626.         jb      .fat_err
  2627. ; set length to full number of clusters
  2628.         sub     [edi+28], ecx
  2629. .start_extend:
  2630.         pop     ecx
  2631. ; now do extend
  2632.         push    edx
  2633.         mov     edx, 2          ; start scan from cluster 2
  2634. .extend_loop:
  2635.         cmp     [edi+28], ecx
  2636.         jae     .extend_done
  2637. ; add new cluster
  2638.         push    eax
  2639.         call    get_free_FAT
  2640.         jc      .disk_full
  2641.         mov     edx, [ebp+FAT.fatEND]
  2642.         call    set_FAT
  2643.         mov     edx, eax
  2644.         pop     eax
  2645.         test    eax, eax
  2646.         jz      .first_cluster
  2647.         push    edx
  2648.         call    set_FAT
  2649.         pop     edx
  2650.         jmp     @f
  2651. .first_cluster:
  2652.         ror     edx, 16
  2653.         mov     [edi+20], dx
  2654.         ror     edx, 16
  2655.         mov     [edi+26], dx
  2656. @@:
  2657.         push    ecx
  2658.         mov     ecx, -1
  2659.         call    add_disk_free_space
  2660.         pop     ecx
  2661.         mov     eax, edx
  2662.         add     [edi+28], esi
  2663.         jmp     .extend_loop
  2664. .extend_done:
  2665.         mov     [edi+28], ecx
  2666.         pop     edx esi
  2667.         xor     eax, eax        ; CF=0
  2668.         ret
  2669. .device_err3:
  2670.         pop     edx
  2671.         jmp     .device_err2
  2672. .disk_full:
  2673.         pop     eax edx esi
  2674.         movi    eax, ERROR_DISK_FULL
  2675.         stc
  2676.         ret
  2677.  
  2678. ;----------------------------------------------------------------
  2679. fat_SetFileEnd:
  2680.         call    fat_lock
  2681.         call    hd_find_lfn
  2682.         jc      .reteax
  2683. ; must not be directory
  2684.         test    byte [edi+11], 10h
  2685.         jnz     .access_denied
  2686. ; file size must not exceed 4 Gb
  2687.         cmp     dword [ebx+8], 0
  2688.         jnz     .endOfFile
  2689.         push    eax     ; save directory sector
  2690. ; set file modification date/time to current
  2691.         call    get_time_for_file
  2692.         mov     [edi+22], ax    ; last write
  2693.         call    get_date_for_file
  2694.         mov     [edi+24], ax    ; last write
  2695.         mov     [edi+18], ax    ; last access
  2696.         mov     eax, [ebx+4]
  2697.         cmp     eax, [edi+28]
  2698.         jb      .truncate
  2699.         ja      .expand
  2700.         pop     eax
  2701.         lea     ebx, [ebp+FAT.buffer]
  2702.         call    fs_write32_sys
  2703.         test    eax, eax
  2704.         jnz     .errorDevice
  2705.         push    0
  2706.         jmp     .ret
  2707.  
  2708. .access_denied:
  2709.         push    ERROR_ACCESS_DENIED
  2710.         jmp     .ret
  2711.  
  2712. .endOfFile:
  2713.         push    ERROR_END_OF_FILE
  2714.         jmp     .ret
  2715.  
  2716. .errorDevice:
  2717.         push    ERROR_DEVICE
  2718.         jmp     .ret
  2719.  
  2720. .expand:
  2721.         push    ebx ebp ecx
  2722.         push    dword [edi+28]  ; save old size
  2723.         mov     ecx, eax
  2724.         call    hd_extend_file
  2725.         push    eax             ; return code
  2726.         jnc     .expand_ok
  2727.         cmp     al, ERROR_DISK_FULL
  2728.         jnz     .pop_ret
  2729. .expand_ok: ; save directory
  2730.         mov     eax, [edi+28]
  2731.         xchg    eax, [esp+20]
  2732.         lea     ebx, [ebp+FAT.buffer]
  2733.         call    fs_write32_sys
  2734.         test    eax, eax
  2735.         jnz     .pop_ret11
  2736.         mov     eax, [esp+20]
  2737.         sub     eax, [esp+4]
  2738.         cmp     eax, 1000001h
  2739.         jnc     .pop_ret
  2740.         mov     eax, [edi+20-2]
  2741.         mov     ax, [edi+26]
  2742.         mov     edi, eax
  2743.         test    edi, edi
  2744.         jz      .pop_ret
  2745. ; now zero new data
  2746.         push    0
  2747. ; edi=current cluster, [esp]=sector in cluster
  2748. ; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code
  2749. .zero_loop:
  2750.         cmp     edi, 2
  2751.         jb      .error_fat
  2752.         cmp     edi, [ebp+FAT.fatRESERVED]
  2753.         jae     .error_fat
  2754.         sub     dword [esp+8], 0x200
  2755.         jae     .next_cluster
  2756.         lea     eax, [edi-2]
  2757.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2758.         add     eax, [ebp+FAT.DATA_START]
  2759.         add     eax, [esp]
  2760.         cmp     dword [esp+8], -0x200
  2761.         jz      .noread
  2762.         push    eax
  2763.         lea     ebx, [ebp+FAT.buffer]
  2764.         call    fs_read32_app
  2765.         test    eax, eax
  2766.         pop     eax
  2767.         jnz     .err_next
  2768. .noread:
  2769.         mov     ecx, [esp+8]
  2770.         neg     ecx
  2771.         push    edi
  2772.         lea     edi, [ebp+FAT.buffer+0x200]
  2773.         add     edi, [esp+12]
  2774.         push    eax
  2775.         xor     eax, eax
  2776.         mov     [esp+16], eax
  2777.         rep stosb
  2778.         pop     eax
  2779.         pop     edi
  2780.         call    fs_write32_app
  2781.         test    eax, eax
  2782.         jz      .next_cluster
  2783. .err_next:
  2784.         mov     byte [esp+4], ERROR_DEVICE
  2785. .next_cluster:
  2786.         pop     eax
  2787.         sub     dword [esp+20], 0x200
  2788.         jbe     .pop_ret
  2789.         inc     eax
  2790.         push    eax
  2791.         cmp     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2792.         jb      .zero_loop
  2793.         and     dword [esp], 0
  2794.         mov     eax, edi
  2795.         call    get_FAT
  2796.         mov     edi, eax
  2797.         jnc     .zero_loop
  2798.         pop     eax
  2799. .pop_ret11:
  2800.         mov     byte [esp], ERROR_DEVICE
  2801. .pop_ret:
  2802.         call    update_disk
  2803.         pop     eax ecx ecx ebp ebx ecx
  2804. .reteax:
  2805.         push    eax
  2806. .ret:
  2807.         call    fat_unlock
  2808.         pop     eax
  2809.         ret
  2810.  
  2811. .error_fat:
  2812.         pop     eax
  2813.         mov     byte [esp], ERROR_FS_FAIL
  2814.         jmp     .pop_ret
  2815.  
  2816. .error_fat2:
  2817.         pop     eax ecx eax
  2818.         call    update_disk
  2819.         push    ERROR_FS_FAIL
  2820.         jmp     .ret
  2821.  
  2822. .truncate:
  2823.         mov     [edi+28], eax
  2824.         push    ecx
  2825.         mov     ecx, [edi+20-2]
  2826.         mov     cx, [edi+26]
  2827.         push    eax
  2828.         test    eax, eax
  2829.         jz      .zero_size
  2830. @@: ; find new last cluster
  2831.         cmp     ecx, 2
  2832.         jb      .error_fat2
  2833.         cmp     ecx, [ebp+FAT.fatRESERVED]
  2834.         jae     .error_fat2
  2835.         mov     eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  2836.         shl     eax, 9
  2837.         sub     [esp], eax
  2838.         jbe     @f
  2839.         mov     eax, ecx
  2840.         call    get_FAT
  2841.         mov     ecx, eax
  2842.         jnc     @b
  2843. .device_err3:
  2844.         pop     eax ecx eax
  2845.         call    update_disk
  2846.         push    ERROR_DEVICE
  2847.         jmp     .ret
  2848.  
  2849. @@:
  2850. ; we will zero data at the end of last sector - remember it
  2851.         push    ecx
  2852. ; terminate FAT chain
  2853.         push    edx
  2854.         mov     eax, ecx
  2855.         mov     edx, [ebp+FAT.fatEND]
  2856.         call    set_FAT
  2857.         mov     eax, edx
  2858.         pop     edx
  2859.         jnc     @f
  2860. .device_err4:
  2861.         pop     ecx
  2862.         jmp     .device_err3
  2863.  
  2864. .zero_size:
  2865.         and     word [edi+20], 0
  2866.         and     word [edi+26], 0
  2867.         push    0
  2868.         mov     eax, ecx
  2869. @@:
  2870. ; delete FAT chain
  2871.         call    clear_cluster_chain
  2872.         jc      .device_err4
  2873. ; save directory
  2874.         mov     eax, [esp+12]
  2875.         push    ebx
  2876.         lea     ebx, [ebp+FAT.buffer]
  2877.         call    fs_write32_sys
  2878.         pop     ebx
  2879.         test    eax, eax
  2880.         jnz     .device_err4
  2881. ; zero last sector, ignore errors
  2882.         pop     ecx
  2883.         pop     eax
  2884.         dec     ecx
  2885.         imul    ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  2886.         add     ecx, [ebp+FAT.DATA_START]
  2887.         push    eax
  2888.         sar     eax, 9
  2889.         add     ecx, eax
  2890.         pop     eax
  2891.         and     eax, 0x1FF
  2892.         jz      .truncate_done
  2893.         push    ebx eax
  2894.         mov     eax, ecx
  2895.         lea     ebx, [ebp+FAT.buffer]
  2896.         call    fs_read32_app
  2897.         pop     eax
  2898.         lea     edi, [ebp+FAT.buffer+eax]
  2899.         push    ecx
  2900.         mov     ecx, 0x200
  2901.         sub     ecx, eax
  2902.         xor     eax, eax
  2903.         rep stosb
  2904.         pop     eax
  2905.         call    fs_write32_app
  2906.         pop     ebx
  2907. .truncate_done:
  2908.         pop     ecx eax
  2909.         call    update_disk
  2910.         call    fat_unlock
  2911.         xor     eax, eax
  2912.         ret
  2913.  
  2914. ;----------------------------------------------------------------
  2915. fat_GetFileInfo:
  2916.         cmp     byte [esi], 0
  2917.         jz      .volume
  2918.         call    fat_lock
  2919.         call    hd_find_lfn
  2920.         jc      @f
  2921.         push    ebp
  2922.         xor     ebp, ebp
  2923.         mov     esi, [ebx+16]
  2924.         mov     dword [esi+4], ebp
  2925.         call    fat_entry_to_bdfe2
  2926.         pop     ebp
  2927.         xor     eax, eax
  2928. @@:
  2929.         push    eax
  2930.         call    fat_unlock
  2931.         pop     eax
  2932. @@:
  2933.         ret
  2934.  
  2935. .volume:
  2936.         mov     eax, dword[ebp+FAT.Length]
  2937.         mov     edx, dword[ebp+FAT.Length+4]
  2938.         mov     edi, [ebx+16]
  2939.         shld    edx, eax, 9
  2940.         shl     eax, 9
  2941.         mov     [edi+36], edx
  2942.         mov     [edi+32], eax
  2943.         mov     eax, [ebx+8]
  2944.         mov     byte [edi], 8
  2945.         mov     [edi+4], eax
  2946.         test    eax, eax
  2947.         jz      @b
  2948.         lea     esi, [ebp+FAT.volumeLabel]
  2949.         mov     ecx, 11
  2950. @@:
  2951.         mov     byte [esi+ecx], 0
  2952.         dec     ecx
  2953.         jz      @f
  2954.         cmp     byte [esi+ecx], ' '
  2955.         jz      @b
  2956. @@:
  2957.         mov     cl, 12
  2958.         add     edi, 40
  2959.         cmp     eax, 2
  2960.         jz      @f
  2961.         rep movsb
  2962.         xor     eax, eax
  2963.         ret
  2964.  
  2965. @@:
  2966.         lodsb
  2967.         stosw
  2968.         loop    @b
  2969.         ret
  2970.  
  2971. ;----------------------------------------------------------------
  2972. fat_SetFileInfo:
  2973.         call    fat_lock
  2974.         call    hd_find_lfn
  2975.         jc      @f
  2976.         push    eax
  2977.         mov     edx, [ebx+16]
  2978.         call    bdfe_to_fat_entry
  2979.         pop     eax
  2980.         lea     ebx, [ebp+FAT.buffer]
  2981.         call    fs_write32_sys
  2982.         call    update_disk
  2983.         xor     eax, eax
  2984. @@:
  2985.         push    eax
  2986.         call    fat_unlock
  2987.         pop     eax
  2988.         ret
  2989.  
  2990. ;----------------------------------------------------------------
  2991. fat_Delete:
  2992.         call    fat_lock
  2993.         and     [ebp+FAT.longname_sec1], 0
  2994.         and     [ebp+FAT.longname_sec2], 0
  2995.         call    hd_find_lfn
  2996.         jc      .notFound
  2997.         cmp     dword [edi], '.   '
  2998.         jz      .access_denied2
  2999.         cmp     dword [edi], '..  '
  3000.         jz      .access_denied2
  3001.         test    byte [edi+11], 10h
  3002.         jz      .dodel
  3003. ; we can delete only empty folders!
  3004.         pushad
  3005.         mov     esi, [edi+20-2]
  3006.         mov     si, [edi+26]
  3007.         xor     ecx, ecx
  3008.         lea     eax, [esi-2]
  3009.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  3010.         add     eax, [ebp+FAT.DATA_START]
  3011.         lea     ebx, [ebp+FAT.buffer]
  3012.         call    fs_read32_sys
  3013.         test    eax, eax
  3014.         jnz     .err1
  3015.         lea     eax, [ebx+0x200]
  3016.         add     ebx, 2*0x20
  3017. .checkempty:
  3018.         cmp     byte [ebx], 0
  3019.         jz      .empty
  3020.         cmp     byte [ebx], 0xE5
  3021.         jnz     .notempty
  3022.         add     ebx, 0x20
  3023.         cmp     ebx, eax
  3024.         jb      .checkempty
  3025.         inc     ecx
  3026.         cmp     ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
  3027.         jb      @f
  3028.         mov     eax, esi
  3029.         call    get_FAT
  3030.         jc      .err1
  3031.         cmp     eax, 2
  3032.         jb      .error_fat
  3033.         cmp     eax, [ebp+FAT.fatRESERVED]
  3034.         jae     .empty
  3035.         mov     esi, eax
  3036.         xor     ecx, ecx
  3037. @@:
  3038.         lea     eax, [esi-2]
  3039.         imul    eax, [ebp+FAT.SECTORS_PER_CLUSTER]
  3040.         add     eax, [ebp+FAT.DATA_START]
  3041.         add     eax, ecx
  3042.         lea     ebx, [ebp+FAT.buffer]
  3043.         call    fs_read32_sys
  3044.         test    eax, eax
  3045.         lea     eax, [ebx+0x200]
  3046.         jz      .checkempty
  3047. .err1:
  3048.         popad
  3049. .err2:
  3050.         push    ERROR_DEVICE
  3051. .ret:
  3052.         call    fat_unlock
  3053.         pop     eax
  3054.         ret
  3055.  
  3056. .notFound:
  3057.         push    ERROR_FILE_NOT_FOUND
  3058.         jmp     .ret
  3059.  
  3060. .error_fat:
  3061.         popad
  3062.         push    ERROR_FS_FAIL
  3063.         jmp     .ret
  3064.  
  3065. .notempty:
  3066.         popad
  3067. .access_denied2:
  3068.         push    ERROR_ACCESS_DENIED
  3069.         jmp     .ret
  3070.  
  3071. .empty:
  3072.         popad
  3073.         push    eax ebx
  3074.         lea     ebx, [ebp+FAT.buffer]
  3075.         call    fs_read32_sys
  3076.         test    eax, eax
  3077.         pop     ebx eax
  3078.         jnz     .err2
  3079. .dodel:
  3080.         push    eax
  3081.         mov     eax, [edi+20-2]
  3082.         mov     ax, [edi+26]
  3083.         xchg    eax, [esp]
  3084. ; delete folder entry
  3085.         mov     byte [edi], 0xE5
  3086. ; delete LFN (if present)
  3087. .lfndel:
  3088.         lea     edx, [ebp+FAT.buffer]
  3089.         cmp     edi, edx
  3090.         ja      @f
  3091.         cmp     [ebp+FAT.longname_sec2], 0
  3092.         jz      .lfndone
  3093.         push    [ebp+FAT.longname_sec2]
  3094.         push    [ebp+FAT.longname_sec1]
  3095.         pop     [ebp+FAT.longname_sec2]
  3096.         and     [ebp+FAT.longname_sec1], 0
  3097.         push    ebx
  3098.         mov     ebx, edx
  3099.         call    fs_write32_sys
  3100.         mov     eax, [esp+4]
  3101.         call    fs_read32_sys
  3102.         pop     ebx
  3103.         pop     eax
  3104.         lea     edi, [ebp+FAT.buffer+0x200]
  3105. @@:
  3106.         sub     edi, 0x20
  3107.         cmp     byte [edi], 0xE5
  3108.         jz      .lfndone
  3109.         cmp     byte [edi+11], 0xF
  3110.         jnz     .lfndone
  3111.         mov     byte [edi], 0xE5
  3112.         jmp     .lfndel
  3113. .lfndone:
  3114.         push    ebx
  3115.         lea     ebx, [ebp+FAT.buffer]
  3116.         call    fs_write32_sys
  3117.         pop     ebx
  3118. ; delete FAT chain
  3119.         pop     eax
  3120.         call    clear_cluster_chain
  3121.         call    update_disk
  3122.         call    fat_unlock
  3123.         xor     eax, eax
  3124.         ret
  3125.  
  3126. ;----------------------------------------------------------------
  3127. fat_Rename:
  3128. ; in: edi -> new path string in UTF-8
  3129.         push    esi edi
  3130.         call    fat_lock
  3131.         call    hd_find_lfn
  3132.         pop     ebx
  3133.         jc      .error
  3134.         sub     esp, 32
  3135.         mov     esi, edi
  3136.         mov     edi, esp
  3137.         mov     ecx, 8
  3138.         rep movsd
  3139.         mov     [ebp+FAT.createOption], 2
  3140.         mov     esi, ebx
  3141.         call    fat_CreateFile.rename
  3142.         add     esp, 32
  3143.         pop     esi
  3144.         test    eax, eax
  3145.         jnz     .ret
  3146.         push    eax
  3147.         mov     [ebp+FAT.longname_sec1], eax
  3148.         mov     [ebp+FAT.longname_sec2], eax
  3149.         call    hd_find_lfn
  3150.         jc      .error
  3151.         mov     byte [edi], 0xE5
  3152.         jmp     fat_Delete.lfndel
  3153.  
  3154. .error:
  3155.         push    eax
  3156.         call    fat_unlock
  3157.         pop     eax ebx
  3158. .ret:
  3159.         ret
  3160.