Subversion Repositories Kolibri OS

Rev

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

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