Subversion Repositories Kolibri OS

Rev

Rev 5984 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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