Subversion Repositories Kolibri OS

Rev

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

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