Subversion Repositories Kolibri OS

Rev

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