Subversion Repositories Kolibri OS

Rev

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