Subversion Repositories Kolibri OS

Rev

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