Subversion Repositories Kolibri OS

Rev

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