Subversion Repositories Kolibri OS

Rev

Rev 139 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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