Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 3742 $
  9.  
  10. struct NTFS PARTITION
  11. Lock                    MUTEX ?    ; currently operations with one partition
  12.                                    ; can not be executed in parallel since the
  13.                                    ; legacy code is not ready; this mutex guards
  14.                                    ; all operations
  15. sectors_per_cluster     dd      ?
  16. mft_cluster             dd      ?
  17. mftmirr_cluster         dd      ?
  18. frs_size                dd      ?       ; FRS size in bytes
  19. iab_size                dd      ?       ; IndexAllocationBuffer size in bytes
  20. frs_buffer              dd      ?
  21. iab_buffer              dd      ?
  22. mft_retrieval           dd      ?
  23. mft_retrieval_size      dd      ?
  24. mft_retrieval_alloc     dd      ?
  25. mft_retrieval_end       dd      ?
  26. cur_index_size          dd      ?
  27. cur_index_buf           dd      ?
  28.  
  29. ntfs_cur_attr   dd      ?
  30. ntfs_cur_iRecord dd     ?
  31. ntfs_cur_offs   dd      ?       ; in sectors
  32. ntfs_cur_size   dd      ?       ; in sectors
  33. ntfs_cur_buf    dd      ?
  34. ntfs_cur_read   dd      ?       ; [output]
  35. ntfs_bCanContinue db    ?
  36.                 rb      3
  37.  
  38. cur_subnode_size        dd      ?
  39. ntfs_attr_iRecord       dd      ?
  40. ntfs_attr_iBaseRecord   dd      ?
  41. ntfs_attr_offs          dd      ?
  42. ntfs_attr_list          dd      ?
  43. ntfs_attr_size          dq      ?
  44. ntfs_cur_tail           dd      ?
  45.  
  46. ntfs_attrlist_buf       rb      0x400
  47. ntfs_attrlist_mft_buf   rb      0x400
  48. ntfs_bitmap_buf         rb      0x400
  49. ends
  50.  
  51. iglobal
  52. align 4
  53. ntfs_user_functions:
  54.         dd      ntfs_free
  55.         dd      (ntfs_user_functions_end - ntfs_user_functions - 4) / 4
  56.         dd      ntfs_Read
  57.         dd      ntfs_ReadFolder
  58.         dd      ntfs_Rewrite
  59.         dd      ntfs_Write
  60.         dd      ntfs_SetFileEnd
  61.         dd      ntfs_GetFileInfo
  62.         dd      ntfs_SetFileInfo
  63.         dd      0
  64.         dd      ntfs_Delete
  65.         dd      ntfs_CreateFolder
  66. ntfs_user_functions_end:
  67. endg
  68.  
  69. ntfs_test_bootsec:
  70. ; in: ebx->buffer, edx=size of partition
  71. ; out: CF set <=> invalid
  72. ; 1. Name=='NTFS    '
  73.         cmp     dword [ebx+3], 'NTFS'
  74.         jnz     .no
  75.         cmp     dword [ebx+7], '    '
  76.         jnz     .no
  77. ; 2. Number of bytes per sector is the same as for physical device
  78. ; (that is, 0x200 for hard disk)
  79.         cmp     word [ebx+11], 0x200
  80.         jnz     .no
  81. ; 3. Number of sectors per cluster must be power of 2
  82.         movzx   eax, byte [ebx+13]
  83.         dec     eax
  84.         js      .no
  85.         test    al, [ebx+13]
  86.         jnz     .no
  87. ; 4. FAT parameters must be zero
  88.         cmp     word [ebx+14], 0
  89.         jnz     .no
  90.         cmp     dword [ebx+16], 0
  91.         jnz     .no
  92.         cmp     byte [ebx+20], 0
  93.         jnz     .no
  94.         cmp     word [ebx+22], 0
  95.         jnz     .no
  96.         cmp     dword [ebx+32], 0
  97.         jnz     .no
  98. ; 5. Number of sectors <= partition size
  99.         cmp     dword [ebx+0x2C], 0
  100.         ja      .no
  101.         cmp     [ebx+0x28], edx
  102.         ja      .no
  103. ; 6. $MFT and $MFTMirr clusters must be within partition
  104.         cmp     dword [ebx+0x34], 0
  105.         ja      .no
  106.         push    edx
  107.         movzx   eax, byte [ebx+13]
  108.         mul     dword [ebx+0x30]
  109.         test    edx, edx
  110.         pop     edx
  111.         jnz     .no
  112.         cmp     eax, edx
  113.         ja      .no
  114.         cmp     dword [ebx+0x3C], 0
  115.         ja      .no
  116.         push    edx
  117.         movzx   eax, byte [ebx+13]
  118.         mul     dword [ebx+0x38]
  119.         test    edx, edx
  120.         pop     edx
  121.         jnz     .no
  122.         cmp     eax, edx
  123.         ja      .no
  124. ; 7. Clusters per FRS must be either negative and in [-31,-9] or positive and power of 2
  125.         movsx   eax, byte [ebx+0x40]
  126.         cmp     al, -31
  127.         jl      .no
  128.         cmp     al, -9
  129.         jle     @f
  130.         dec     eax
  131.         js      .no
  132.         test    [ebx+0x40], al
  133.         jnz     .no
  134. @@:
  135. ; 8. Same for clusters per IndexAllocationBuffer
  136.         movsx   eax, byte [ebx+0x44]
  137.         cmp     al, -31
  138.         jl      .no
  139.         cmp     al, -9
  140.         jle     @f
  141.         dec     eax
  142.         js      .no
  143.         test    [ebx+0x44], al
  144.         jnz     .no
  145. @@:
  146. ; OK, this is correct NTFS bootsector
  147.         clc
  148.         ret
  149. .no:
  150. ; No, this bootsector isn't NTFS
  151.         stc
  152.         ret
  153.  
  154. proc ntfs_create_partition
  155.         mov     edx, dword [ebp+PARTITION.Length]
  156.         cmp     dword [esp+4], 0
  157.         jz      .boot_read_ok
  158.         add     ebx, 512
  159.         lea     eax, [edx-1]
  160.         call    fs_read32_sys
  161.         test    eax, eax
  162.         jnz     @f
  163.         call    ntfs_test_bootsec
  164.         jnc     .ntfs_setup
  165. @@:
  166.         mov     eax, edx
  167.         shr     eax, 1
  168.         call    fs_read32_sys
  169.         test    eax, eax
  170.         jnz     .nope                   ; no chance...
  171. .boot_read_ok:
  172.         call    ntfs_test_bootsec
  173.         jnc     .ntfs_setup
  174. .nope:
  175.         xor     eax, eax
  176.         jmp     .exit
  177.  
  178. .ntfs_setup:
  179. ; By given bootsector, initialize some NTFS variables
  180.         movi    eax, sizeof.NTFS
  181.         call    malloc
  182.         test    eax, eax
  183.         jz      .exit
  184.         mov     ecx, dword [ebp+PARTITION.FirstSector]
  185.         mov     dword [eax+NTFS.FirstSector], ecx
  186.         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
  187.         mov     dword [eax+NTFS.FirstSector+4], ecx
  188.         mov     ecx, dword [ebp+PARTITION.Length]
  189.         mov     dword [eax+NTFS.Length], ecx
  190.         mov     ecx, dword [ebp+PARTITION.Length+4]
  191.         mov     dword [eax+NTFS.Length+4], ecx
  192.         mov     ecx, [ebp+PARTITION.Disk]
  193.         mov     [eax+NTFS.Disk], ecx
  194.         mov     [eax+NTFS.FSUserFunctions], ntfs_user_functions
  195.         push    ebx ebp esi
  196.         mov     ebp, eax
  197.  
  198.         lea     ecx, [ebp+NTFS.Lock]
  199.         call    mutex_init
  200.  
  201.         movzx   eax, byte [ebx+13]
  202.         mov     [ebp+NTFS.sectors_per_cluster], eax
  203.         mov     eax, [ebx+0x28]
  204.         mov     dword [ebp+NTFS.Length], eax
  205.         and     dword [ebp+NTFS.Length+4], 0
  206.         mov     eax, [ebx+0x30]
  207.         mov     [ebp+NTFS.mft_cluster], eax
  208.         mov     eax, [ebx+0x38]
  209.         mov     [ebp+NTFS.mftmirr_cluster], eax
  210.         movsx   eax, byte [ebx+0x40]
  211.         test    eax, eax
  212.         js      .1
  213.         mul     [ebp+NTFS.sectors_per_cluster]
  214.         shl     eax, 9
  215.         jmp     .2
  216. .1:
  217.         neg     eax
  218.         mov     ecx, eax
  219.         mov     eax, 1
  220.         shl     eax, cl
  221. .2:
  222.         mov     [ebp+NTFS.frs_size], eax
  223.         movsx   eax, byte [ebx+0x44]
  224.         test    eax, eax
  225.         js      .3
  226.         mul     [ebp+NTFS.sectors_per_cluster]
  227.         shl     eax, 9
  228.         jmp     .4
  229. .3:
  230.         neg     eax
  231.         mov     ecx, eax
  232.         mov     eax, 1
  233.         shl     eax, cl
  234. .4:
  235.         mov     [ebp+NTFS.iab_size], eax
  236. ; allocate space for buffers
  237.         add     eax, [ebp+NTFS.frs_size]
  238.         push    eax
  239.         call    kernel_alloc
  240.         test    eax, eax
  241.         jz      .fail_free
  242.         mov     [ebp+NTFS.frs_buffer], eax
  243.         add     eax, [ebp+NTFS.frs_size]
  244.         mov     [ebp+NTFS.iab_buffer], eax
  245. ; read $MFT disposition
  246.         mov     eax, [ebp+NTFS.mft_cluster]
  247.         mul     [ebp+NTFS.sectors_per_cluster]
  248.         call    ntfs_read_frs_sector
  249.         test    eax, eax
  250.         jnz     .usemirr
  251.         cmp     dword [ebx], 'FILE'
  252.         jnz     .usemirr
  253.         call    ntfs_restore_usa_frs
  254.         jnc     .mftok
  255. .usemirr:
  256.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  257.         mul     [ebp+NTFS.sectors_per_cluster]
  258.         call    ntfs_read_frs_sector
  259.         test    eax, eax
  260.         jnz     @f
  261.         cmp     dword [ebx], 'FILE'
  262.         jnz     @f
  263.         call    ntfs_restore_usa_frs
  264.         jnc     .mftok
  265. @@:
  266. ; $MFT and $MFTMirr invalid!
  267. .fail_free_frs:
  268.         push    [ebp+NTFS.frs_buffer]
  269.         call    kernel_free
  270. .fail_free:
  271.         mov     eax, ebp
  272.         call    free
  273.         xor     eax, eax
  274. .pop_exit:
  275.         pop     esi ebp ebx
  276. .exit:
  277.         cmp     dword [esp+4], 0
  278.         jz      @f
  279.         sub     ebx, 512
  280. @@:
  281.         ret
  282. .fail_free_mft:
  283.         push    [ebp+NTFS.mft_retrieval]
  284.         call    kernel_free
  285.         jmp     .fail_free_frs
  286. .mftok:
  287. ; read $MFT table retrieval information
  288. ; start with one page, increase if not enough (when MFT too fragmented)
  289.         push    ebx
  290.         push    0x1000
  291.         call    kernel_alloc
  292.         pop     ebx
  293.         test    eax, eax
  294.         jz      .fail_free_frs
  295.         mov     [ebp+NTFS.mft_retrieval], eax
  296.         and     [ebp+NTFS.mft_retrieval_size], 0
  297.         mov     [ebp+NTFS.mft_retrieval_alloc], 0x1000/8
  298. ; $MFT base record must contain unnamed non-resident $DATA attribute
  299.         movzx   eax, word [ebx+14h]
  300.         add     eax, ebx
  301. .scandata:
  302.         cmp     dword [eax], -1
  303.         jz      .fail_free_mft
  304.         cmp     dword [eax], 0x80
  305.         jnz     @f
  306.         cmp     byte [eax+9], 0
  307.         jz      .founddata
  308. @@:
  309.         add     eax, [eax+4]
  310.         jmp     .scandata
  311. .founddata:
  312.         cmp     byte [eax+8], 0
  313.         jz      .fail_free_mft
  314. ; load first portion of $DATA attribute retrieval information
  315.         mov     edx, [eax+0x18]
  316.         mov     [ebp+NTFS.mft_retrieval_end], edx
  317.         mov     esi, eax
  318.         movzx   eax, word [eax+0x20]
  319.         add     esi, eax
  320.         sub     esp, 10h
  321. .scanmcb:
  322.         call    ntfs_decode_mcb_entry
  323.         jnc     .scanmcbend
  324.         call    .get_mft_retrieval_ptr
  325.         mov     edx, [esp]      ; block length
  326.         mov     [eax], edx
  327.         mov     edx, [esp+8]    ; block addr (relative)
  328.         mov     [eax+4], edx
  329.         inc     [ebp+NTFS.mft_retrieval_size]
  330.         jmp     .scanmcb
  331. .scanmcbend:
  332.         add     esp, 10h
  333. ; there may be other portions of $DATA attribute in auxiliary records;
  334. ; if they will be needed, they will be loaded later
  335.  
  336.         mov     [ebp+NTFS.cur_index_size], 0x1000/0x200
  337.         push    0x1000
  338.         call    kernel_alloc
  339.         test    eax, eax
  340.         jz      .fail_free_mft
  341.         mov     [ebp+NTFS.cur_index_buf], eax
  342.  
  343.         mov     eax, ebp
  344.         jmp     .pop_exit
  345. endp
  346.  
  347. .get_mft_retrieval_ptr:
  348.         pushad
  349.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  350.         cmp     eax, [ebp+NTFS.mft_retrieval_alloc]
  351.         jnz     .ok
  352.         add     eax, 0x1000/8
  353.         mov     [ebp+NTFS.mft_retrieval_alloc], eax
  354.         shl     eax, 3
  355.         push    eax
  356.         call    kernel_alloc
  357.         test    eax, eax
  358.         jnz     @f
  359.         popad
  360.         add     esp, 14h
  361.         jmp     .fail_free_mft
  362. @@:
  363.         mov     esi, [ebp+NTFS.mft_retrieval]
  364.         mov     edi, eax
  365.         mov     ecx, [ebp+NTFS.mft_retrieval_size]
  366.         add     ecx, ecx
  367.         rep movsd
  368.         push    [ebp+NTFS.mft_retrieval]
  369.         mov     [ebp+NTFS.mft_retrieval], eax
  370.         call    kernel_free
  371.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  372. .ok:
  373.         shl     eax, 3
  374.         add     eax, [ebp+NTFS.mft_retrieval]
  375.         mov     [esp+28], eax
  376.         popad
  377.         ret
  378.  
  379. proc ntfs_free
  380.         push    ebx
  381.         xchg    ebx, eax
  382.         stdcall kernel_free, [ebx+NTFS.frs_buffer]
  383.         stdcall kernel_free, [ebx+NTFS.mft_retrieval]
  384.         stdcall kernel_free, [ebx+NTFS.cur_index_buf]
  385.         xchg    ebx, eax
  386.         call    free
  387.         pop     ebx
  388.         ret
  389. endp
  390.  
  391. proc ntfs_lock
  392.         lea     ecx, [ebp+NTFS.Lock]
  393.         jmp     mutex_lock
  394. endp
  395.  
  396. proc ntfs_unlock
  397.         lea     ecx, [ebp+NTFS.Lock]
  398.         jmp     mutex_unlock
  399. endp
  400.  
  401. ntfs_read_frs_sector:
  402.         push    ecx
  403.         mov     ebx, [ebp+NTFS.frs_buffer]
  404.         push    ebx
  405.         mov     ecx, [ebp+NTFS.frs_size]
  406.         shr     ecx, 9
  407.         push    ecx
  408.         mov     ecx, eax
  409. @@:
  410.         mov     eax, ecx
  411.         call    fs_read32_sys
  412.         test    eax, eax
  413.         jnz     .fail
  414.         add     ebx, 0x200
  415.         inc     ecx
  416.         dec     dword [esp]
  417.         jnz     @b
  418.         pop     eax
  419. .fail:
  420.         pop     ebx
  421.         pop     ecx
  422.         ret
  423.  
  424. ntfs_read_attr:
  425. ; in: variables in ebp+NTFS.*
  426. ; out: [ebp+NTFS.ntfs_cur_read]
  427. ; out: CF=1 => notfound, in this case eax=0 => disk ok, otherwise eax=disk error code
  428.         xor     eax, eax
  429.         pushad
  430.         and     [ebp+NTFS.ntfs_cur_read], 0
  431.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  432.         jnz     .nomft
  433.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  434.         jnz     .nomft
  435.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  436.         inc     eax
  437.         mul     [ebp+NTFS.sectors_per_cluster]
  438.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  439.         jbe     .nomft
  440. ; precalculated part of $Mft $DATA
  441.         mov     esi, [ebp+NTFS.mft_retrieval]
  442.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  443.         xor     edx, edx
  444.         div     [ebp+NTFS.sectors_per_cluster]
  445. ; eax = VCN, edx = offset in sectors from beginning of cluster
  446.         xor     ecx, ecx        ; ecx will contain LCN
  447. .mftscan:
  448.         add     ecx, [esi+4]
  449.         sub     eax, [esi]
  450.         jb      @f
  451.         add     esi, 8
  452.         push    eax
  453.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  454.         shl     eax, 3
  455.         add     eax, [ebp+NTFS.mft_retrieval]
  456.         cmp     eax, esi
  457.         pop     eax
  458.         jnz     .mftscan
  459.         jmp     .nomft
  460. @@:
  461.         push    ecx
  462.         add     ecx, eax
  463.         add     ecx, [esi]
  464.         push    eax
  465.         push    edx
  466.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  467.         mul     ecx
  468. ; eax = sector on partition
  469.         pop     edx
  470.         add     eax, edx
  471.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  472.         pop     ecx
  473.         neg     ecx
  474.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  475.         sub     ecx, edx
  476.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  477.         jb      @f
  478.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  479. @@:
  480. ; ecx = number of sequential sectors to read
  481.         push    eax
  482.         call    fs_read32_sys
  483.         pop     edx
  484.         test    eax, eax
  485.         jnz     .errread
  486.         add     [ebp+NTFS.ntfs_cur_read], 0x200
  487.         dec     [ebp+NTFS.ntfs_cur_size]
  488.         inc     [ebp+NTFS.ntfs_cur_offs]
  489.         add     ebx, 0x200
  490.         mov     [ebp+NTFS.ntfs_cur_buf], ebx
  491.         lea     eax, [edx+1]
  492.         loop    @b
  493.         pop     ecx
  494.         xor     eax, eax
  495.         xor     edx, edx
  496.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  497.         jz      @f
  498.         add     esi, 8
  499.         push    eax
  500.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  501.         shl     eax, 3
  502.         add     eax, [ebp+NTFS.mft_retrieval]
  503.         cmp     eax, esi
  504.         pop     eax
  505.         jz      .nomft
  506.         jmp     .mftscan
  507. @@:
  508.         popad
  509.         ret
  510. .errread:
  511.         pop     ecx
  512. .errret:
  513.         mov     [esp+28], eax
  514.         stc
  515.         popad
  516.         ret
  517. .nomft:
  518. ; 1. Read file record.
  519. ; N.B. This will do recursive call of read_attr for $MFT::$Data.
  520.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  521.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  522.         and     [ebp+NTFS.ntfs_attr_list], 0
  523.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  524.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  525.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  526.         call    ntfs_read_file_record
  527.         jc      .errret
  528. ; 2. Find required attribute.
  529.         mov     eax, [ebp+NTFS.frs_buffer]
  530. ; a) For auxiliary records, read base record
  531. ; N.B. If base record is present,
  532. ;      base iRecord may be 0 (for $Mft), but SequenceNumber is nonzero
  533.         cmp     dword [eax+24h], 0
  534.         jz      @f
  535.         mov     eax, [eax+20h]
  536. ;        test    eax, eax
  537. ;        jz      @f
  538. .beginfindattr:
  539.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  540.         call    ntfs_read_file_record
  541.         jc      .errret
  542. @@:
  543. ; b) Scan for required attribute and for $ATTR_LIST
  544.         mov     eax, [ebp+NTFS.frs_buffer]
  545.         movzx   ecx, word [eax+14h]
  546.         add     eax, ecx
  547.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  548.         and     [ebp+NTFS.ntfs_attr_offs], 0
  549. .scanattr:
  550.         cmp     dword [eax], -1
  551.         jz      .scandone
  552.         cmp     dword [eax], ecx
  553.         jz      .okattr
  554.         cmp     [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  555.         jnz     .scancont
  556.         cmp     dword [eax], 0x20       ; $ATTR_LIST
  557.         jnz     .scancont
  558.         mov     [ebp+NTFS.ntfs_attr_list], eax
  559.         jmp     .scancont
  560. .okattr:
  561. ; ignore named $DATA attributes (aka NTFS streams)
  562.         cmp     ecx, 0x80
  563.         jnz     @f
  564.         cmp     byte [eax+9], 0
  565.         jnz     .scancont
  566. @@:
  567.         mov     [ebp+NTFS.ntfs_attr_offs], eax
  568. .scancont:
  569.         add     eax, [eax+4]
  570.         jmp     .scanattr
  571. .continue:
  572.         pushad
  573.         and     [ebp+NTFS.ntfs_cur_read], 0
  574. .scandone:
  575. ; c) Check for required offset and length
  576.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  577.         jecxz   .noattr
  578.         push    [ebp+NTFS.ntfs_cur_size]
  579.         push    [ebp+NTFS.ntfs_cur_read]
  580.         call    .doreadattr
  581.         pop     edx
  582.         pop     ecx
  583.         jc      @f
  584.         cmp     [ebp+NTFS.ntfs_bCanContinue], 0
  585.         jz      @f
  586.         sub     edx, [ebp+NTFS.ntfs_cur_read]
  587.         neg     edx
  588.         shr     edx, 9
  589.         sub     ecx, edx
  590.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  591.         jnz     .not_in_cur
  592. @@:
  593.         popad
  594.         ret
  595. .noattr:
  596. .not_in_cur:
  597.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x20
  598.         jz      @f
  599.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  600.         test    ecx, ecx
  601.         jnz     .lookattr
  602. .ret_is_attr:
  603.         and     dword [esp+28], 0
  604.         cmp     [ebp+NTFS.ntfs_attr_offs], 1     ; CF set <=> ntfs_attr_offs == 0
  605.         popad
  606.         ret
  607. .lookattr:
  608. ; required attribute or required offset was not found in base record;
  609. ; it may be present in auxiliary records;
  610. ; scan $ATTR_LIST
  611.         mov     eax, [ebp+NTFS.ntfs_attr_iBaseRecord]
  612.         cmp     eax, -1
  613.         jz      @f
  614.         call    ntfs_read_file_record
  615.         jc      .errret
  616.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  617. @@:
  618.         push    [ebp+NTFS.ntfs_cur_offs]
  619.         push    [ebp+NTFS.ntfs_cur_size]
  620.         push    [ebp+NTFS.ntfs_cur_read]
  621.         push    [ebp+NTFS.ntfs_cur_buf]
  622.         push    dword [ebp+NTFS.ntfs_attr_size]
  623.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  624.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  625.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  626.         and     [ebp+NTFS.ntfs_cur_offs], 0
  627.         mov     [ebp+NTFS.ntfs_cur_size], 2
  628.         and     [ebp+NTFS.ntfs_cur_read], 0
  629.         lea     eax, [ebp+NTFS.ntfs_attrlist_buf]
  630.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  631.         jnz     @f
  632.         lea     eax, [ebp+NTFS.ntfs_attrlist_mft_buf]
  633. @@:
  634.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  635.         push    eax
  636.         call    .doreadattr
  637.         pop     esi
  638.         mov     edx, 1
  639.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  640.         pop     dword [ebp+NTFS.ntfs_attr_size]
  641.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  642.         pop     [ebp+NTFS.ntfs_cur_buf]
  643.         pop     [ebp+NTFS.ntfs_cur_read]
  644.         pop     [ebp+NTFS.ntfs_cur_size]
  645.         pop     [ebp+NTFS.ntfs_cur_offs]
  646.         jc      .errret
  647.         or      edi, -1
  648.         lea     ecx, [ecx+esi-1Ah]
  649. .scanliststart:
  650.         push    ecx
  651.         mov     eax, [ebp+NTFS.ntfs_cur_attr]
  652. .scanlist:
  653.         cmp     esi, [esp]
  654.         jae     .scanlistdone
  655.         cmp     eax, [esi]
  656.         jz      @f
  657. .scanlistcont:
  658.         movzx   ecx, word [esi+4]
  659.         add     esi, ecx
  660.         jmp     .scanlist
  661. @@:
  662. ; ignore named $DATA attributes (aka NTFS streams)
  663.         cmp     eax, 0x80
  664.         jnz     @f
  665.         cmp     byte [esi+6], 0
  666.         jnz     .scanlistcont
  667. @@:
  668.         push    eax
  669.         mov     eax, [esi+8]
  670.         test    eax, eax
  671.         jnz     .testf
  672.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  673.         and     eax, dword [ebp+NTFS.ntfs_attr_size+4]
  674.         cmp     eax, -1
  675.         jnz     .testfz
  676. ; if attribute is in auxiliary records, its size is defined only in first
  677.         mov     eax, [esi+10h]
  678.         call    ntfs_read_file_record
  679.         jnc     @f
  680. .errret_pop:
  681.         pop     ecx ecx
  682.         jmp     .errret
  683. .errret2_pop:
  684.         xor     eax, eax
  685.         jmp     .errret_pop
  686. @@:
  687.         mov     eax, [ebp+NTFS.frs_buffer]
  688.         movzx   ecx, word [eax+14h]
  689.         add     eax, ecx
  690.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  691. @@:
  692.         cmp     dword [eax], -1
  693.         jz      .errret2_pop
  694.         cmp     dword [eax], ecx
  695.         jz      @f
  696. .l1:
  697.         add     eax, [eax+4]
  698.         jmp     @b
  699. @@:
  700.         cmp     eax, 0x80
  701.         jnz     @f
  702.         cmp     byte [eax+9], 0
  703.         jnz     .l1
  704. @@:
  705.         cmp     byte [eax+8], 0
  706.         jnz     .sdnores
  707.         mov     eax, [eax+10h]
  708.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  709.         and     dword [ebp+NTFS.ntfs_attr_size+4], 0
  710.         jmp     .testfz
  711. .sdnores:
  712.         mov     ecx, [eax+30h]
  713.         mov     dword [ebp+NTFS.ntfs_attr_size], ecx
  714.         mov     ecx, [eax+34h]
  715.         mov     dword [ebp+NTFS.ntfs_attr_size+4], ecx
  716. .testfz:
  717.         xor     eax, eax
  718. .testf:
  719.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  720.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  721.         pop     eax
  722.         ja      @f
  723.         mov     edi, [esi+10h]  ; keep previous iRecord
  724.         jmp     .scanlistcont
  725. @@:
  726.         pop     ecx
  727. .scanlistfound:
  728.         cmp     edi, -1
  729.         jnz     @f
  730.         popad
  731.         ret
  732. @@:
  733.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  734.         mov     [ebp+NTFS.ntfs_attr_iBaseRecord], eax
  735.         mov     eax, edi
  736.         jmp     .beginfindattr
  737. .scanlistdone:
  738.         pop     ecx
  739.         sub     ecx, ebp
  740.         sub     ecx, NTFS.ntfs_attrlist_buf-1Ah
  741.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  742.         jnz     @f
  743.         sub     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  744. @@:
  745.         cmp     ecx, 0x400
  746.         jnz     .scanlistfound
  747.         inc     edx
  748.         push    esi edi
  749.         lea     esi, [ebp+NTFS.ntfs_attrlist_buf+0x200]
  750.         lea     edi, [ebp+NTFS.ntfs_attrlist_buf]
  751.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  752.         jnz     @f
  753.         lea     esi, [ebp+NTFS.ntfs_attrlist_mft_buf+0x200]
  754.         lea     edi, [ebp+NTFS.ntfs_attrlist_mft_buf]
  755. @@:
  756.         mov     ecx, 0x200/4
  757.         rep movsd
  758.         mov     eax, edi
  759.         pop     edi esi
  760.         sub     esi, 0x200
  761.         push    [ebp+NTFS.ntfs_cur_offs]
  762.         push    [ebp+NTFS.ntfs_cur_size]
  763.         push    [ebp+NTFS.ntfs_cur_read]
  764.         push    [ebp+NTFS.ntfs_cur_buf]
  765.         push    dword [ebp+NTFS.ntfs_attr_size]
  766.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  767.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  768.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  769.         mov     [ebp+NTFS.ntfs_cur_offs], edx
  770.         mov     [ebp+NTFS.ntfs_cur_size], 1
  771.         and     [ebp+NTFS.ntfs_cur_read], 0
  772.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  773.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  774.         push    esi edx edi
  775.         call    .doreadattr
  776.         pop     edi edx esi
  777.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  778.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  779.         pop     dword [ebp+NTFS.ntfs_attr_size]
  780.         pop     [ebp+NTFS.ntfs_cur_buf]
  781.         pop     [ebp+NTFS.ntfs_cur_read]
  782.         pop     [ebp+NTFS.ntfs_cur_size]
  783.         pop     [ebp+NTFS.ntfs_cur_offs]
  784.         jc      .errret
  785.         lea     ecx, [ecx+ebp+NTFS.ntfs_attrlist_buf+0x200-0x1A]
  786.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  787.         jnz     .scanliststart
  788.         add     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  789.         jmp     .scanliststart
  790.  
  791. .doreadattr:
  792.         mov     [ebp+NTFS.ntfs_bCanContinue], 0
  793.         cmp     byte [ecx+8], 0
  794.         jnz     .nonresident
  795.         mov     eax, [ecx+10h]  ; length
  796.         mov     esi, eax
  797.         mov     edx, [ebp+NTFS.ntfs_cur_offs]
  798.         shr     eax, 9
  799.         cmp     eax, edx
  800.         jb      .okret
  801.         shl     edx, 9
  802.         sub     esi, edx
  803.         movzx   eax, word [ecx+14h]
  804.         add     edx, eax
  805.         add     edx, ecx        ; edx -> data
  806.         mov     eax, [ebp+NTFS.ntfs_cur_size]
  807.         cmp     eax, (0xFFFFFFFF shr 9)+1
  808.         jbe     @f
  809.         mov     eax, (0xFFFFFFFF shr 9)+1
  810. @@:
  811.         shl     eax, 9
  812.         cmp     eax, esi
  813.         jbe     @f
  814.         mov     eax, esi
  815. @@:
  816. ; eax = length, edx -> data
  817.         mov     [ebp+NTFS.ntfs_cur_read], eax
  818.         mov     ecx, eax
  819.         mov     eax, edx
  820.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  821.         call    memmove
  822.         and     [ebp+NTFS.ntfs_cur_size], 0      ; CF=0
  823.         ret
  824. .nonresident:
  825. ; Not all auxiliary records contain correct FileSize info
  826.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  827.         mov     edx, dword [ebp+NTFS.ntfs_attr_size+4]
  828.         push    eax
  829.         and     eax, edx
  830.         cmp     eax, -1
  831.         pop     eax
  832.         jnz     @f
  833.         mov     eax, [ecx+30h]  ; FileSize
  834.         mov     edx, [ecx+34h]
  835.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  836.         mov     dword [ebp+NTFS.ntfs_attr_size+4], edx
  837. @@:
  838.         add     eax, 0x1FF
  839.         adc     edx, 0
  840.         shrd    eax, edx, 9
  841.         sub     eax, [ebp+NTFS.ntfs_cur_offs]
  842.         ja      @f
  843. ; return with nothing read
  844.         and     [ebp+NTFS.ntfs_cur_size], 0
  845. .okret:
  846.         clc
  847.         ret
  848. @@:
  849. ; reduce read length
  850.         and     [ebp+NTFS.ntfs_cur_tail], 0
  851.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  852.         jb      @f
  853.         mov     [ebp+NTFS.ntfs_cur_size], eax
  854.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  855.         and     eax, 0x1FF
  856.         mov     [ebp+NTFS.ntfs_cur_tail], eax
  857. @@:
  858.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  859.         jz      .okret
  860.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  861.         xor     edx, edx
  862.         div     [ebp+NTFS.sectors_per_cluster]
  863.         sub     eax, [ecx+10h]  ; first_vbo
  864.         jb      .okret
  865. ; eax = cluster, edx = starting sector
  866.         sub     esp, 10h
  867.         movzx   esi, word [ecx+20h]     ; mcb_info_ofs
  868.         add     esi, ecx
  869.         xor     edi, edi
  870. .readloop:
  871.         call    ntfs_decode_mcb_entry
  872.         jnc     .break
  873.         add     edi, [esp+8]
  874.         sub     eax, [esp]
  875.         jae     .readloop
  876.         push    ecx
  877.         push    eax
  878.         add     eax, [esp+8]
  879.         add     eax, edi
  880.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  881.         add     eax, edx
  882.         pop     ecx
  883.         neg     ecx
  884.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  885.         sub     ecx, edx
  886.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  887.         jb      @f
  888.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  889. @@:
  890.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  891. @@:
  892.         push    eax
  893.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  894.         jnz     .sys
  895.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  896.         jz      .sys
  897.         call    fs_read32_app
  898.         jmp     .appsys
  899. .sys:
  900.         call    fs_read32_sys
  901. .appsys:
  902.         pop     edx
  903.         test    eax, eax
  904.         jnz     .errread2
  905.         add     ebx, 0x200
  906.         mov     [ebp+NTFS.ntfs_cur_buf], ebx
  907.         lea     eax, [edx+1]
  908.         add     [ebp+NTFS.ntfs_cur_read], 0x200
  909.         dec     [ebp+NTFS.ntfs_cur_size]
  910.         inc     [ebp+NTFS.ntfs_cur_offs]
  911.         loop    @b
  912.         pop     ecx
  913.         xor     eax, eax
  914.         xor     edx, edx
  915.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  916.         jnz     .readloop
  917.         add     esp, 10h
  918.         mov     eax, [ebp+NTFS.ntfs_cur_tail]
  919.         test    eax, eax
  920.         jz      @f
  921.         sub     eax, 0x200
  922.         add     [ebp+NTFS.ntfs_cur_read], eax
  923. @@:
  924.         clc
  925.         ret
  926. .errread2:
  927.         pop     ecx
  928.         add     esp, 10h
  929.         stc
  930.         ret
  931. .break:
  932.         add     esp, 10h        ; CF=0
  933.         mov     [ebp+NTFS.ntfs_bCanContinue], 1
  934.         ret
  935.  
  936. ntfs_read_file_record:
  937. ; in: eax=iRecord
  938. ; out: [ebp+NTFS.frs_buffer] contains information
  939. ;      CF=1 - failed, in this case eax=0 => something with FS, eax nonzero => disk error
  940. ; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
  941.         push    ecx edx
  942.         mov     ecx, [ebp+NTFS.frs_size]
  943.         mul     ecx
  944.         shrd    eax, edx, 9
  945.         shr     edx, 9
  946.         jnz     .errret
  947.         push    [ebp+NTFS.ntfs_attr_iRecord]
  948.         push    [ebp+NTFS.ntfs_attr_iBaseRecord]
  949.         push    [ebp+NTFS.ntfs_attr_offs]
  950.         push    [ebp+NTFS.ntfs_attr_list]
  951.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  952.         push    dword [ebp+NTFS.ntfs_attr_size]
  953.         push    [ebp+NTFS.ntfs_cur_iRecord]
  954.         push    [ebp+NTFS.ntfs_cur_attr]
  955.         push    [ebp+NTFS.ntfs_cur_offs]
  956.         push    [ebp+NTFS.ntfs_cur_size]
  957.         push    [ebp+NTFS.ntfs_cur_buf]
  958.         push    [ebp+NTFS.ntfs_cur_read]
  959.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  960.         and     [ebp+NTFS.ntfs_cur_iRecord], 0   ; $Mft
  961.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  962.         shr     ecx, 9
  963.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  964.         mov     eax, [ebp+NTFS.frs_buffer]
  965.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  966.         call    ntfs_read_attr
  967.         mov     edx, [ebp+NTFS.ntfs_cur_read]
  968.         pop     [ebp+NTFS.ntfs_cur_read]
  969.         pop     [ebp+NTFS.ntfs_cur_buf]
  970.         pop     [ebp+NTFS.ntfs_cur_size]
  971.         pop     [ebp+NTFS.ntfs_cur_offs]
  972.         pop     [ebp+NTFS.ntfs_cur_attr]
  973.         pop     [ebp+NTFS.ntfs_cur_iRecord]
  974.         pop     dword [ebp+NTFS.ntfs_attr_size]
  975.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  976.         pop     [ebp+NTFS.ntfs_attr_list]
  977.         pop     [ebp+NTFS.ntfs_attr_offs]
  978.         pop     [ebp+NTFS.ntfs_attr_iBaseRecord]
  979.         pop     [ebp+NTFS.ntfs_attr_iRecord]
  980.         jc      .ret
  981.         cmp     edx, [ebp+NTFS.frs_size]
  982.         jnz     .errret
  983.         mov     eax, [ebp+NTFS.frs_buffer]
  984.         cmp     dword [eax], 'FILE'
  985.         jnz     .errret
  986.         push    ebx
  987.         mov     ebx, eax
  988.         call    ntfs_restore_usa_frs
  989.         pop     ebx
  990.         jc      .errret
  991. .ret:
  992.         pop     edx ecx
  993.         ret
  994. .errret:
  995.         pop     edx ecx
  996.         xor     eax, eax
  997.         stc
  998.         ret
  999.  
  1000. ntfs_restore_usa_frs:
  1001.         mov     eax, [ebp+NTFS.frs_size]
  1002. ntfs_restore_usa:
  1003.         pushad
  1004.         shr     eax, 9
  1005.         mov     ecx, eax
  1006.         inc     eax
  1007.         cmp     [ebx+6], ax
  1008.         jnz     .err
  1009.         movzx   eax, word [ebx+4]
  1010.         lea     esi, [eax+ebx]
  1011.         lodsw
  1012.         mov     edx, eax
  1013.         lea     edi, [ebx+0x1FE]
  1014. @@:
  1015.         cmp     [edi], dx
  1016.         jnz     .err
  1017.         lodsw
  1018.         stosw
  1019.         add     edi, 0x1FE
  1020.         loop    @b
  1021.         popad
  1022.         clc
  1023.         ret
  1024. .err:
  1025.         popad
  1026.         stc
  1027.         ret
  1028.  
  1029. ntfs_decode_mcb_entry:
  1030.         push    eax ecx edi
  1031.         lea     edi, [esp+16]
  1032.         xor     eax, eax
  1033.         lodsb
  1034.         test    al, al
  1035.         jz      .end
  1036.         mov     ecx, eax
  1037.         and     ecx, 0xF
  1038.         cmp     ecx, 8
  1039.         ja      .end
  1040.         push    ecx
  1041.         rep movsb
  1042.         pop     ecx
  1043.         sub     ecx, 8
  1044.         neg     ecx
  1045.         cmp     byte [esi-1], 80h
  1046.         jae     .end
  1047.         push    eax
  1048.         xor     eax, eax
  1049.         rep stosb
  1050.         pop     ecx
  1051.         shr     ecx, 4
  1052.         cmp     ecx, 8
  1053.         ja      .end
  1054.         push    ecx
  1055.         rep movsb
  1056.         pop     ecx
  1057.         sub     ecx, 8
  1058.         neg     ecx
  1059.         cmp     byte [esi-1], 80h
  1060.         cmc
  1061.         sbb     eax, eax
  1062.         rep stosb
  1063.         stc
  1064. .end:
  1065.         pop     edi ecx eax
  1066.         ret
  1067.  
  1068. unichar_toupper:
  1069.         push    eax
  1070.         call    uni2ansi_char
  1071.         cmp     al, '_'
  1072.         jz      .unk
  1073.         add     esp, 4
  1074.         call    char_toupper
  1075.         jmp     ansi2uni_char
  1076. .unk:
  1077.         pop     eax
  1078.         ret
  1079.  
  1080. ntfs_find_lfn:
  1081. ; in: esi+[esp+4] -> name
  1082. ; out: CF=1 - file not found
  1083. ;      else CF=0, [ebp+NTFS.ntfs_cur_iRecord] valid, eax->record in parent directory
  1084.         mov     [ebp+NTFS.ntfs_cur_iRecord], 5   ; start parse from root cluster
  1085. .doit2:
  1086.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1087.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1088.         mov     eax, [ebp+NTFS.cur_index_size]
  1089.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1090.         mov     eax, [ebp+NTFS.cur_index_buf]
  1091.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1092.         call    ntfs_read_attr
  1093.         jnc     @f
  1094. .ret:
  1095.         ret     4
  1096. @@:
  1097.         xor     eax, eax
  1098.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1099.         jc      .ret
  1100.         pushad
  1101.         mov     esi, [ebp+NTFS.cur_index_buf]
  1102.         mov     eax, [esi+14h]
  1103.         add     eax, 10h
  1104.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1105.         jae     .readok1
  1106.         add     eax, 1FFh
  1107.         shr     eax, 9
  1108.         cmp     eax, [ebp+NTFS.cur_index_size]
  1109.         ja      @f
  1110. .stc_ret:
  1111.         popad
  1112.         stc
  1113.         ret     4
  1114. @@:
  1115. ; reallocate
  1116.         push    eax
  1117.         push    [ebp+NTFS.cur_index_buf]
  1118.         call    kernel_free
  1119.         pop     eax
  1120.         mov     [ebp+NTFS.cur_index_size], eax
  1121.         push    eax
  1122.         call    kernel_alloc
  1123.         test    eax, eax
  1124.         jnz     @f
  1125.         and     [ebp+NTFS.cur_index_size], 0
  1126.         and     [ebp+NTFS.cur_index_buf], 0
  1127.         jmp     .stc_ret
  1128. @@:
  1129.         mov     [ebp+NTFS.cur_index_buf], eax
  1130.         popad
  1131.         jmp     .doit2
  1132. .readok1:
  1133.         mov     edx, [esi+8]    ; subnode_size
  1134.         shr     edx, 9
  1135.         cmp     edx, [ebp+NTFS.cur_index_size]
  1136.         jbe     .ok2
  1137.         push    esi edx
  1138.         push    edx
  1139.         call    kernel_alloc
  1140.         pop     edx esi
  1141.         test    eax, eax
  1142.         jz      .stc_ret
  1143.         mov     edi, eax
  1144.         mov     ecx, [ebp+NTFS.cur_index_size]
  1145.         shl     ecx, 9-2
  1146.         rep movsd
  1147.         mov     esi, eax
  1148.         mov     [ebp+NTFS.cur_index_size], edx
  1149.         push    esi edx
  1150.         push    [ebp+NTFS.cur_index_buf]
  1151.         call    kernel_free
  1152.         pop     edx esi
  1153.         mov     [ebp+NTFS.cur_index_buf], esi
  1154. .ok2:
  1155.         add     esi, 10h
  1156.         mov     edi, [esp+4]
  1157. ; edi -> name, esi -> current index data, edx = subnode size
  1158. .scanloop:
  1159.         add     esi, [esi]
  1160. .scanloopint:
  1161.         test    byte [esi+0Ch], 2
  1162.         jnz     .subnode
  1163.         push    esi
  1164.         add     esi, 0x52
  1165.         movzx   ecx, byte [esi-2]
  1166.         push    edi
  1167. @@:
  1168.         lodsw
  1169.         call    unichar_toupper
  1170.         push    eax
  1171.         mov     al, [edi]
  1172.         inc     edi
  1173.         cmp     al, '/'
  1174.         jz      .slash
  1175.         call    char_toupper
  1176.         call    ansi2uni_char
  1177.         cmp     ax, [esp]
  1178.         pop     eax
  1179.         loopz   @b
  1180.         jz      .found
  1181.         pop     edi
  1182.         pop     esi
  1183.         jb      .subnode
  1184. .scanloopcont:
  1185.         movzx   eax, word [esi+8]
  1186.         add     esi, eax
  1187.         jmp     .scanloopint
  1188. .slash:
  1189.         pop     eax
  1190.         pop     edi
  1191.         pop     esi
  1192. .subnode:
  1193.         test    byte [esi+0Ch], 1
  1194.         jz      .notfound
  1195.         movzx   eax, word [esi+8]
  1196.         mov     eax, [esi+eax-8]
  1197.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  1198.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1199.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1200.         mov     [ebp+NTFS.ntfs_cur_size], edx
  1201.         mov     eax, [ebp+NTFS.cur_index_buf]
  1202.         mov     esi, eax
  1203.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1204.         push    edx
  1205.         call    ntfs_read_attr
  1206.         pop     edx
  1207.         mov     eax, edx
  1208.         shl     eax, 9
  1209.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1210.         jnz     .notfound
  1211.         cmp     dword [esi], 'INDX'
  1212.         jnz     .notfound
  1213.         mov     ebx, esi
  1214.         call    ntfs_restore_usa
  1215.         jc      .notfound
  1216.         add     esi, 0x18
  1217.         jmp     .scanloop
  1218. .notfound:
  1219.         popad
  1220.         stc
  1221.         ret     4
  1222. .found:
  1223.         cmp     byte [edi], 0
  1224.         jz      .done
  1225.         cmp     byte [edi], '/'
  1226.         jz      .next
  1227.         pop     edi
  1228.         pop     esi
  1229.         jmp     .scanloopcont
  1230. .done:
  1231. .next:
  1232.         pop     esi
  1233.         pop     esi
  1234.         mov     eax, [esi]
  1235.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1236.         mov     [esp+1Ch], esi
  1237.         mov     [esp+4], edi
  1238.         popad
  1239.         inc     esi
  1240.         cmp     byte [esi-1], 0
  1241.         jnz     .doit2
  1242.         cmp     dword [esp+4], 0
  1243.         jz      @f
  1244.         mov     esi, [esp+4]
  1245.         mov     dword [esp+4], 0
  1246.         jmp     .doit2
  1247. @@:
  1248.         ret     4
  1249.  
  1250. ;----------------------------------------------------------------
  1251. ; ntfs_Read - NTFS implementation of reading a file
  1252. ; in:  ebp = pointer to NTFS structure
  1253. ; in:  esi+[esp+4] = name
  1254. ; in:  ebx = pointer to parameters from sysfunc 70
  1255. ; out: eax, ebx = return values for sysfunc 70
  1256. ;----------------------------------------------------------------
  1257. ntfs_Read:
  1258.         cmp     byte [esi], 0
  1259.         jnz     @f
  1260.         or      ebx, -1
  1261.         movi    eax, ERROR_ACCESS_DENIED
  1262.         ret
  1263. @@:
  1264.         call    ntfs_lock
  1265.         stdcall ntfs_find_lfn, [esp+4]
  1266.         jnc     .found
  1267.         call    ntfs_unlock
  1268.         or      ebx, -1
  1269.         movi    eax, ERROR_FILE_NOT_FOUND
  1270.         ret
  1271. .found:
  1272.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  1273.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1274.         and     [ebp+NTFS.ntfs_cur_size], 0
  1275.         call    ntfs_read_attr
  1276.         jnc     @f
  1277.         call    ntfs_unlock
  1278.         or      ebx, -1
  1279.         movi    eax, ERROR_ACCESS_DENIED
  1280.         ret
  1281. @@:
  1282.         pushad
  1283.         and     dword [esp+10h], 0
  1284.         xor     eax, eax
  1285.         cmp     dword [ebx+8], 0x200
  1286.         jb      @f
  1287. .eof0:
  1288.         popad
  1289.         xor     ebx, ebx
  1290. .eof:
  1291.         movi    eax, ERROR_END_OF_FILE
  1292.         push    eax
  1293.         call    ntfs_unlock
  1294.         pop     eax
  1295.         ret
  1296. @@:
  1297.         mov     ecx, [ebx+12]
  1298.         mov     edx, [ebx+16]
  1299.         mov     eax, [ebx+4]
  1300.         test    eax, 0x1FF
  1301.         jz      .alignedstart
  1302.         push    edx
  1303.         mov     edx, [ebx+8]
  1304.         shrd    eax, edx, 9
  1305.         pop     edx
  1306.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1307.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1308.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1309.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1310.         call    ntfs_read_attr.continue
  1311.         mov     eax, [ebx+4]
  1312.         and     eax, 0x1FF
  1313.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf+eax]
  1314.         sub     eax, [ebp+NTFS.ntfs_cur_read]
  1315.         jae     .eof0
  1316.         neg     eax
  1317.         push    ecx
  1318.         cmp     ecx, eax
  1319.         jb      @f
  1320.         mov     ecx, eax
  1321. @@:
  1322.         mov     [esp+10h+4], ecx
  1323.         mov     edi, edx
  1324.         rep movsb
  1325.         mov     edx, edi
  1326.         pop     ecx
  1327.         sub     ecx, [esp+10h]
  1328.         jnz     @f
  1329. .retok:
  1330.         popad
  1331.         call    ntfs_unlock
  1332.         xor     eax, eax
  1333.         ret
  1334. @@:
  1335.         cmp     [ebp+NTFS.ntfs_cur_read], 0x200
  1336.         jz      .alignedstart
  1337. .eof_ebx:
  1338.         popad
  1339.         jmp     .eof
  1340. .alignedstart:
  1341.         mov     eax, [ebx+4]
  1342.         push    edx
  1343.         mov     edx, [ebx+8]
  1344.         add     eax, 511
  1345.         adc     edx, 0
  1346.         shrd    eax, edx, 9
  1347.         pop     edx
  1348. .zero1:
  1349.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1350.         mov     [ebp+NTFS.ntfs_cur_buf], edx
  1351.         mov     eax, ecx
  1352.         shr     eax, 9
  1353.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1354.         add     eax, [ebp+NTFS.ntfs_cur_offs]
  1355.         push    eax
  1356.         call    ntfs_read_attr.continue
  1357.         pop     [ebp+NTFS.ntfs_cur_offs]
  1358.         mov     eax, [ebp+NTFS.ntfs_cur_read]
  1359.         add     [esp+10h], eax
  1360.         mov     eax, ecx
  1361.         and     eax, not 0x1FF
  1362.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1363.         jnz     .eof_ebx
  1364.         and     ecx, 0x1FF
  1365.         jz      .retok
  1366.         add     edx, [ebp+NTFS.ntfs_cur_read]
  1367.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1368.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1369.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1370.         call    ntfs_read_attr.continue
  1371.         cmp     [ebp+NTFS.ntfs_cur_read], ecx
  1372.         jb      @f
  1373.         mov     [ebp+NTFS.ntfs_cur_read], ecx
  1374. @@:
  1375.         xchg    ecx, [ebp+NTFS.ntfs_cur_read]
  1376.         push    ecx
  1377.         mov     edi, edx
  1378.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf]
  1379.         add     [esp+10h+4], ecx
  1380.         rep movsb
  1381.         pop     ecx
  1382.         xor     eax, eax
  1383.         cmp     ecx, [ebp+NTFS.ntfs_cur_read]
  1384.         jz      @f
  1385.         mov     al, ERROR_END_OF_FILE
  1386. @@:
  1387.         mov     [esp+1Ch], eax
  1388.         call    ntfs_unlock
  1389.         popad
  1390.         ret
  1391.  
  1392. ;----------------------------------------------------------------
  1393. ; ntfs_ReadFolder - NTFS implementation of reading a folder
  1394. ; in:  ebp = pointer to NTFS structure
  1395. ; in:  esi+[esp+4] = name
  1396. ; in:  ebx = pointer to parameters from sysfunc 70
  1397. ; out: eax, ebx = return values for sysfunc 70
  1398. ;----------------------------------------------------------------
  1399. ntfs_ReadFolder:
  1400.         call    ntfs_lock
  1401.         mov     eax, 5          ; root cluster
  1402.         cmp     byte [esi], 0
  1403.         jz      .doit
  1404.         stdcall ntfs_find_lfn, [esp+4]
  1405.         jnc     .doit2
  1406. .notfound:
  1407.         or      ebx, -1
  1408.         push    ERROR_FILE_NOT_FOUND
  1409. .pop_ret:
  1410.         call    ntfs_unlock
  1411.         pop     eax
  1412.         ret
  1413. .doit:
  1414.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1415. .doit2:
  1416.         mov     [ebp+NTFS.ntfs_cur_attr], 0x10   ; $STANDARD_INFORMATION
  1417.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1418.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1419.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1420.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1421.         call    ntfs_read_attr
  1422.         jc      .notfound
  1423.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1424.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1425.         mov     eax, [ebp+NTFS.cur_index_size]
  1426.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1427.         mov     eax, [ebp+NTFS.cur_index_buf]
  1428.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1429.         call    ntfs_read_attr
  1430.         jnc     .ok
  1431.         test    eax, eax
  1432.         jz      .notfound
  1433.         or      ebx, -1
  1434.         push    11
  1435.         jmp     .pop_ret
  1436. .ok:
  1437.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1438.         jae     @f
  1439.         or      ebx, -1
  1440. .fserr:
  1441.         push    ERROR_FAT_TABLE
  1442.         jmp     .pop_ret
  1443. @@:
  1444.         pushad
  1445.         mov     esi, [ebp+NTFS.cur_index_buf]
  1446.         mov     eax, [esi+14h]
  1447.         add     eax, 10h
  1448.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1449.         jae     .readok1
  1450.         add     eax, 1FFh
  1451.         shr     eax, 9
  1452.         cmp     eax, [ebp+NTFS.cur_index_size]
  1453.         ja      @f
  1454.         popad
  1455.         jmp     .fserr
  1456. @@:
  1457. ; reallocate
  1458.         push    eax
  1459.         push    [ebp+NTFS.cur_index_buf]
  1460.         call    kernel_free
  1461.         pop     eax
  1462.         mov     [ebp+NTFS.cur_index_size], eax
  1463.         push    eax
  1464.         call    kernel_alloc
  1465.         test    eax, eax
  1466.         jnz     @f
  1467.         and     [ebp+NTFS.cur_index_size], 0
  1468.         and     [ebp+NTFS.cur_index_buf], 0
  1469. .nomem:
  1470.         call    ntfs_unlock
  1471.         popad
  1472.         or      ebx, -1
  1473.         movi    eax, 12
  1474.         ret
  1475. @@:
  1476.         mov     [ebp+NTFS.cur_index_buf], eax
  1477.         popad
  1478.         jmp     .doit2
  1479. .readok1:
  1480.         mov     edx, [esi+8]    ; subnode_size
  1481.         shr     edx, 9
  1482.         mov     [ebp+NTFS.cur_subnode_size], edx
  1483.         cmp     edx, [ebp+NTFS.cur_index_size]
  1484.         jbe     .ok2
  1485.         push    esi edx
  1486.         push    edx
  1487.         call    kernel_alloc
  1488.         pop     edx esi
  1489.         test    eax, eax
  1490.         jz      .nomem
  1491.         mov     edi, eax
  1492.         mov     ecx, [ebp+NTFS.cur_index_size]
  1493.         shl     ecx, 9-2
  1494.         rep movsd
  1495.         mov     esi, eax
  1496.         mov     [ebp+NTFS.cur_index_size], edx
  1497.         push    [ebp+NTFS.cur_index_buf]
  1498.         call    kernel_free
  1499.         mov     [ebp+NTFS.cur_index_buf], esi
  1500. .ok2:
  1501.         add     esi, 10h
  1502.         mov     edx, [ebx+16]
  1503.         push    dword [ebx+8]   ; read ANSI/UNICODE name
  1504. ; init header
  1505.         mov     edi, edx
  1506.         mov     ecx, 32/4
  1507.         xor     eax, eax
  1508.         rep stosd
  1509.         mov     byte [edx], 1   ; version
  1510.         mov     ecx, [ebx+12]
  1511.         mov     ebx, [ebx+4]
  1512.         push    edx
  1513.         mov     edx, esp
  1514. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1515. ; ecx = number of blocks to read
  1516. ; edx -> parameters block: dd <output>, dd <flags>
  1517.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 5
  1518.         jz      .skip_specials
  1519. ; dot and dotdot entries
  1520.         push    esi
  1521.         xor     esi, esi
  1522.         call    .add_special_entry
  1523.         inc     esi
  1524.         call    .add_special_entry
  1525.         pop     esi
  1526. .skip_specials:
  1527. ; at first, dump index root
  1528.         add     esi, [esi]
  1529. .dump_root:
  1530.         test    byte [esi+0Ch], 2
  1531.         jnz     .dump_root_done
  1532.         call    .add_entry
  1533.         movzx   eax, word [esi+8]
  1534.         add     esi, eax
  1535.         jmp     .dump_root
  1536. .dump_root_done:
  1537. ; now dump all subnodes
  1538.         push    ecx edi
  1539.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1540.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1541.         mov     ecx, 0x400/4
  1542.         xor     eax, eax
  1543.         rep stosd
  1544.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0   ; $BITMAP
  1545.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1546.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1547.         call    ntfs_read_attr
  1548.         pop     edi ecx
  1549.         push    0       ; save offset in $BITMAP attribute
  1550.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1551. .dumploop:
  1552.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0
  1553.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1554.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1555.         mov     eax, [ebp+NTFS.cur_index_buf]
  1556.         mov     esi, eax
  1557.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1558.         push    [ebp+NTFS.ntfs_cur_offs]
  1559.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1560.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1561.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1562.         call    ntfs_read_attr
  1563.         pop     [ebp+NTFS.ntfs_cur_offs]
  1564.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1565.         shl     eax, 9
  1566.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1567.         jnz     .done
  1568.         push    eax
  1569.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1570.         and     eax, 0x400*8-1
  1571.         bt      dword [ebp+NTFS.ntfs_bitmap_buf], eax
  1572.         pop     eax
  1573.         jnc     .dump_subnode_done
  1574.         cmp     dword [esi], 'INDX'
  1575.         jnz     .dump_subnode_done
  1576.         push    ebx
  1577.         mov     ebx, esi
  1578.         call    ntfs_restore_usa
  1579.         pop     ebx
  1580.         jc      .dump_subnode_done
  1581.         add     esi, 0x18
  1582.         add     esi, [esi]
  1583. .dump_subnode:
  1584.         test    byte [esi+0Ch], 2
  1585.         jnz     .dump_subnode_done
  1586.         call    .add_entry
  1587.         movzx   eax, word [esi+8]
  1588.         add     esi, eax
  1589.         jmp     .dump_subnode
  1590. .dump_subnode_done:
  1591.         inc     [ebp+NTFS.ntfs_cur_offs]
  1592.         test    [ebp+NTFS.ntfs_cur_offs], 0x400*8-1
  1593.         jnz     .dumploop
  1594.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0
  1595.         push    ecx edi
  1596.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1597.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1598.         mov     ecx, 0x400/4
  1599.         xor     eax, eax
  1600.         rep stosd
  1601.         pop     edi ecx
  1602.         pop     eax
  1603.         push    [ebp+NTFS.ntfs_cur_offs]
  1604.         inc     eax
  1605.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1606.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1607.         push    eax
  1608.         call    ntfs_read_attr
  1609.         pop     eax
  1610.         pop     [ebp+NTFS.ntfs_cur_offs]
  1611.         push    eax
  1612.         jmp     .dumploop
  1613. .done:
  1614.         pop     eax
  1615.         pop     edx
  1616.         mov     ebx, [edx+4]
  1617.         pop     edx
  1618.         xor     eax, eax
  1619.         dec     ecx
  1620.         js      @f
  1621.         mov     al, ERROR_END_OF_FILE
  1622. @@:
  1623.         mov     [esp+1Ch], eax
  1624.         mov     [esp+10h], ebx
  1625.         call    ntfs_unlock
  1626.         popad
  1627.         ret
  1628.  
  1629. .add_special_entry:
  1630.         mov     eax, [edx]
  1631.         inc     dword [eax+8]   ; new file found
  1632.         dec     ebx
  1633.         jns     .ret
  1634.         dec     ecx
  1635.         js      .ret
  1636.         inc     dword [eax+4]   ; new file block copied
  1637.         mov     eax, [edx+4]
  1638.         mov     [edi+4], eax
  1639. ;        mov     eax, dword [ntfs_bitmap_buf+0x20]
  1640. ;        or      al, 0x10
  1641.         mov     eax, 0x10
  1642.         stosd
  1643.         scasd
  1644.         push    edx
  1645.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf]
  1646.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+4]
  1647.         call    ntfs_datetime_to_bdfe
  1648.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+0x18]
  1649.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0x1C]
  1650.         call    ntfs_datetime_to_bdfe
  1651.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+8]
  1652.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0xC]
  1653.         call    ntfs_datetime_to_bdfe
  1654.         pop     edx
  1655.         xor     eax, eax
  1656.         stosd
  1657.         stosd
  1658.         mov     al, '.'
  1659.         push    edi ecx
  1660.         lea     ecx, [esi+1]
  1661.         test    byte [edi-0x24], 1
  1662.         jz      @f
  1663.         rep stosw
  1664.         pop     ecx
  1665.         xor     eax, eax
  1666.         stosw
  1667.         pop     edi
  1668.         add     edi, 520
  1669.         ret
  1670. @@:
  1671.         rep stosb
  1672.         pop     ecx
  1673.         xor     eax, eax
  1674.         stosb
  1675.         pop     edi
  1676.         add     edi, 264
  1677. .ret:
  1678.         ret
  1679.  
  1680. .add_entry:
  1681. ; do not return DOS 8.3 names
  1682.         cmp     byte [esi+0x51], 2
  1683.         jz      .ret
  1684. ; do not return system files
  1685. ; ... note that there will be no bad effects if system files also were reported ...
  1686.         cmp     dword [esi], 0x10
  1687.         jb      .ret
  1688.         mov     eax, [edx]
  1689.         inc     dword [eax+8]   ; new file found
  1690.         dec     ebx
  1691.         jns     .ret
  1692.         dec     ecx
  1693.         js      .ret
  1694.         inc     dword [eax+4]   ; new file block copied
  1695.         mov     eax, [edx+4]    ; flags
  1696.         call    ntfs_direntry_to_bdfe
  1697.         push    ecx esi edi
  1698.         movzx   ecx, byte [esi+0x50]
  1699.         add     esi, 0x52
  1700.         test    byte [edi-0x24], 1
  1701.         jz      .ansi
  1702.         shr     ecx, 1
  1703.         rep movsd
  1704.         adc     ecx, ecx
  1705.         rep movsw
  1706.         and     word [edi], 0
  1707.         pop     edi
  1708.         add     edi, 520
  1709.         pop     esi ecx
  1710.         ret
  1711. .ansi:
  1712.         jecxz   .skip
  1713. @@:
  1714.         lodsw
  1715.         call    uni2ansi_char
  1716.         stosb
  1717.         loop    @b
  1718. .skip:
  1719.         xor     al, al
  1720.         stosb
  1721.         pop     edi
  1722.         add     edi, 264
  1723.         pop     esi ecx
  1724.         ret
  1725.  
  1726. ntfs_direntry_to_bdfe:
  1727.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1728.         mov     eax, [esi+48h]
  1729.         test    eax, 0x10000000
  1730.         jz      @f
  1731.         and     eax, not 0x10000000
  1732.         or      al, 0x10
  1733. @@:
  1734.         stosd
  1735.         scasd
  1736.         push    edx
  1737.         mov     eax, [esi+0x18]
  1738.         mov     edx, [esi+0x1C]
  1739.         call    ntfs_datetime_to_bdfe
  1740.         mov     eax, [esi+0x30]
  1741.         mov     edx, [esi+0x34]
  1742.         call    ntfs_datetime_to_bdfe
  1743.         mov     eax, [esi+0x20]
  1744.         mov     edx, [esi+0x24]
  1745.         call    ntfs_datetime_to_bdfe
  1746.         pop     edx
  1747.         mov     eax, [esi+0x40]
  1748.         stosd
  1749.         mov     eax, [esi+0x44]
  1750.         stosd
  1751.         ret
  1752.  
  1753. iglobal
  1754. _24             dd      24
  1755. _60             dd      60
  1756. _10000000       dd      10000000
  1757. days400year     dd      365*400+100-4+1
  1758. days100year     dd      365*100+25-1
  1759. days4year       dd      365*4+1
  1760. days1year       dd      365
  1761. months  dd      31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1762. months2 dd      31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1763. _400            dd      400
  1764. _100            dd      100
  1765. endg
  1766.  
  1767. ntfs_datetime_to_bdfe:
  1768. ; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC
  1769.         push    eax
  1770.         mov     eax, edx
  1771.         xor     edx, edx
  1772.         div     [_10000000]
  1773.         xchg    eax, [esp]
  1774.         div     [_10000000]
  1775.         pop     edx
  1776.     .sec:
  1777. ; edx:eax = number of seconds since January 1, 1601
  1778.         push    eax
  1779.         mov     eax, edx
  1780.         xor     edx, edx
  1781.         div     [_60]
  1782.         xchg    eax, [esp]
  1783.         div     [_60]
  1784.         mov     [edi], dl
  1785.         pop     edx
  1786. ; edx:eax = number of minutes
  1787.         div     [_60]
  1788.         mov     [edi+1], dl
  1789. ; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32)
  1790.         xor     edx, edx
  1791.         div     [_24]
  1792.         mov     [edi+2], dl
  1793.         mov     [edi+3], byte 0
  1794. ; eax = number of days since January 1, 1601
  1795.         xor     edx, edx
  1796.         div     [days400year]
  1797.         imul    eax, 400
  1798.         add     eax, 1601
  1799.         mov     [edi+6], ax
  1800.         mov     eax, edx
  1801.         xor     edx, edx
  1802.         div     [days100year]
  1803.         cmp     al, 4
  1804.         jnz     @f
  1805.         dec     eax
  1806.         add     edx, [days100year]
  1807. @@:
  1808.         imul    eax, 100
  1809.         add     [edi+6], ax
  1810.         mov     eax, edx
  1811.         xor     edx, edx
  1812.         div     [days4year]
  1813.         shl     eax, 2
  1814.         add     [edi+6], ax
  1815.         mov     eax, edx
  1816.         xor     edx, edx
  1817.         div     [days1year]
  1818.         cmp     al, 4
  1819.         jnz     @f
  1820.         dec     eax
  1821.         add     edx, [days1year]
  1822. @@:
  1823.         add     [edi+6], ax
  1824.         push    esi edx
  1825.         mov     esi, months
  1826.         movzx   eax, word [edi+6]
  1827.         test    al, 3
  1828.         jnz     .noleap
  1829.         xor     edx, edx
  1830.         push    eax
  1831.         div     [_400]
  1832.         pop     eax
  1833.         test    edx, edx
  1834.         jz      .leap
  1835.         xor     edx, edx
  1836.         div     [_100]
  1837.         test    edx, edx
  1838.         jz      .noleap
  1839. .leap:
  1840.         mov     esi, months2
  1841. .noleap:
  1842.         pop     edx
  1843.         xor     eax, eax
  1844.         inc     eax
  1845. @@:
  1846.         sub     edx, [esi]
  1847.         jb      @f
  1848.         add     esi, 4
  1849.         inc     eax
  1850.         jmp     @b
  1851. @@:
  1852.         add     edx, [esi]
  1853.         pop     esi
  1854.         inc     edx
  1855.         mov     [edi+4], dl
  1856.         mov     [edi+5], al
  1857.         add     edi, 8
  1858.         ret
  1859.  
  1860. ;----------------------------------------------------------------
  1861. ; ntfs_Rewrite - NTFS implementation of creating a new file
  1862. ; in:  ebp = pointer to NTFS structure
  1863. ; in:  esi+[esp+4] = name
  1864. ; in:  ebx = pointer to parameters from sysfunc 70
  1865. ; out: eax, ebx = return values for sysfunc 70
  1866. ;----------------------------------------------------------------
  1867. ntfs_Rewrite:
  1868. ntfs_CreateFolder:
  1869.         xor     ebx, ebx
  1870.         mov     eax, ERROR_UNSUPPORTED_FS
  1871.         ret
  1872.  
  1873. ;----------------------------------------------------------------
  1874. ; ntfs_Write - NTFS implementation of writing to file
  1875. ; in:  ebp = pointer to NTFS structure
  1876. ; in:  esi+[esp+4] = name
  1877. ; in:  ebx = pointer to parameters from sysfunc 70
  1878. ; out: eax, ebx = return values for sysfunc 70
  1879. ;----------------------------------------------------------------
  1880. ntfs_Write:
  1881.         xor     ebx, ebx
  1882.         mov     eax, ERROR_UNSUPPORTED_FS
  1883.         ret
  1884.  
  1885. ntfs_SetFileEnd:
  1886. ntfs_SetFileInfo:
  1887. ntfs_Delete:
  1888.         mov     eax, ERROR_UNSUPPORTED_FS
  1889.         ret
  1890.  
  1891. ;----------------------------------------------------------------
  1892. ; ntfs_GetFileInfo - NTFS implementation of getting file info
  1893. ; in:  ebp = pointer to NTFS structure
  1894. ; in:  esi+[esp+4] = name
  1895. ; in:  ebx = pointer to parameters from sysfunc 70
  1896. ; out: eax, ebx = return values for sysfunc 70
  1897. ;----------------------------------------------------------------
  1898. ntfs_GetFileInfo:
  1899.         cmp     byte [esi], 0
  1900.         jnz     @f
  1901.         movi    eax, 2
  1902.         ret
  1903. @@:
  1904.         call    ntfs_lock
  1905.         stdcall ntfs_find_lfn, [esp+4]
  1906.         jnc     .doit
  1907.         test    eax, eax
  1908.         movi    eax, ERROR_FILE_NOT_FOUND
  1909.         jz      @f
  1910.         mov     al, 11
  1911. @@:
  1912.         push    eax
  1913.         call    ntfs_unlock
  1914.         pop     eax
  1915.         ret
  1916. .doit:
  1917.         push    esi edi
  1918.         mov     esi, eax
  1919.         mov     edi, [ebx+16]
  1920.         xor     eax, eax
  1921.         call    ntfs_direntry_to_bdfe
  1922.         pop     edi esi
  1923.         call    ntfs_unlock
  1924.         xor     eax, eax
  1925.         ret
  1926.  
  1927.