Author Topic: Trouble with file length under Win64  (Read 1255 times)

Gunther

  • Member
  • *****
  • Posts: 3720
  • Forgive your enemies, but never forget their names
Trouble with file length under Win64
« on: February 10, 2021, 10:11:00 PM »
Here is a small Win64 test program to determine the length of a file:
Code: [Select]
include \masm32\include64\masm64rt.inc
        option casemap: none

        .data

        align      1

msg0               db "This small program is supposed to determine the length of a file:", 10
                   db "-----------------------------------------------------------------", 10, 10, 0
msg0A              db "File length = ", 0
msg0B              db " Bytes", 10, 10, 0                   
msg1               db "All tasks completed.", 10, 10, 0                   
TheFile            db "TestFile.txt", 0  ; our test file
str_format         db "%s", 0            ; string format
uint64_format      db "%llu",0           ; 64 bit unsigned integer

        align      8

hTheFile           dq ?                  ; file handle
TheFileLen         dq ?                  ; file length

       .code

; main             
; Purpose:    Assembly Language Frame
main    proc
        push       rbp                   ; preserve callee save CPU registers
        push       rbx
        push       rdi
        push       rsi
        push       r12
        push       r13
        push       r14
        push       r15

        ; open the file

        invoke     vc_printf, addr str_format, addr msg0
        invoke     CreateFileA, addr TheFile, GENERIC_READ, 0, 0, 0, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING
        mov        hTheFile, rax         ; save file handle

        ; get file size

        invoke     GetFileSize, hTheFile, 0
        mov        TheFileLen, rax       ; save file length

        ; print file size

        invoke     vc_printf, addr str_format, addr msg0A
        invoke     vc_printf, addr uint64_format, addr TheFileLen
        invoke     vc_printf, addr str_format, addr msg0B

        ; close the file
         
        invoke     CloseHandle, hTheFile
        invoke     vc_printf, addr str_format, addr msg1

        waitkey

        pop        r15                   ; restore CPU registers
        pop        r14
        pop        r13
        pop        r12
        pop        rsi
        pop        rdi
        pop        rbx
        pop        rbp
        invoke     ExitProcess, 0
main    endp
        end
It doesn't work as it should. Here's the output:
Quote

This small program is supposed to determine the length of a file:
-----------------------------------------------------------------

File length = 5368717616 Bytes

All tasks completed.
That's the point: the examined file is only 800 bytes in size. So the wrong file length is printed.

What's wrong with that? The archive contains the source, the executable program, the batch file and the test file. It is a small ASCII text file with 20 lines of text. Nothing exciting or disreputable.

Gunther
Get your facts first, and then you can distort them.

jj2007

  • Member
  • *****
  • Posts: 11306
  • Assembler is fun ;-)
    • MasmBasic
Re: Trouble with file length under Win64
« Reply #1 on: February 10, 2021, 10:46:18 PM »
Check your parameters...

Code: [Select]
include \Masm32\MasmBasic\Res\JBasic.inc ; ## builds in 32- or 64-bit mode with UAsm, ML, AsmC ##
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
  Cls
  PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
  PrintLine "This small program is supposed to determine the length of a file:"
  hTheFile equ <rbx>
  mov hTheFile, rv(CreateFileA, Chr$("GetFileSize.asc"), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
  jinvoke     GetFileSize, hTheFile, 0
  Print Str$("The file size is %i bytes\n", rax)
  jinvoke     CloseHandle, hTheFile
  Inkey "all is fine"
EndOfCode

Output:
Code: [Select]
This program was assembled with ml64 in 64-bit format.
This small program is supposed to determine the length of a file:
The file size is 4254 bytes
all is fine

Of course, if you are dealing with large files, you need a second argument to get the high dword.

mikeburr

  • Member
  • **
  • Posts: 132
Re: Trouble with file length under Win64
« Reply #2 on: February 10, 2021, 11:50:30 PM »
the resulting question   is prob ...
is this implying that 1 gig in 4 is allocated for potential file overhead [ sector / track overheads ]????
regards mikeb

TimoVJL

  • Member
  • ****
  • Posts: 695
Re: Trouble with file length under Win64
« Reply #3 on: February 10, 2021, 11:55:08 PM »
Code: [Select]
uint64_format      db "%llu",0           ; 64 bit unsigned integer this might not be usable with msvcrt.dll,
have to use at least msvcr100.dll ?
May the source be with you

Vortex

  • Member
  • *****
  • Posts: 2530
Re: Trouble with file length under Win64
« Reply #4 on: February 10, 2021, 11:58:39 PM »
Hi Gunther,

Can you try this one ?

Code: [Select]
invoke     vc_printf, addr uint64_format, TheFileLen

HSE

  • Member
  • *****
  • Posts: 1612
  • <AMD>< 7-32>
Re: Trouble with file length under Win64
« Reply #5 on: February 11, 2021, 12:17:12 AM »
Hi Gunther,

A good practice (at least when something went wrong :biggrin: ) is:
Code: [Select]
invoke CreateFileA, addr TheFile, GENERIC_READ, 0, 0, 0, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING
.if eax!=INVALID_HANDLE_VALUE                       
        mov hTheFile, rax         ; save file handle
        ...
.else
       ; there is an error
.endif

Regards, HSE

mikeburr

  • Member
  • **
  • Posts: 132
Re: Trouble with file length under Win64
« Reply #6 on: February 11, 2021, 12:38:20 AM »
HSE .. completely agree .... error checking essential ....
in this case
  i doubt whether its failed .. its assumed  a max size/ default  32 bit file [ hence the 4gig comment and overheads comment ]
...  as create disposition 0 not defined in the SDK
with the open existing as security_batch etc etc
regards mikeb

jj2007

  • Member
  • *****
  • Posts: 11306
  • Assembler is fun ;-)
    • MasmBasic
Re: Trouble with file length under Win64
« Reply #7 on: February 11, 2021, 12:48:08 AM »
Check your parameters...

Nope, Mike. As mentioned above, the order of arguments needs to be checked, that's all.

Btw GetFileSize is no good for certain hidden files (CreateFile fails), as I noted when testing for a large file:
Code: [Select]
include \masm32\MasmBasic\MasmBasic.inc
  Init
  .if Exist("C:\hiberfil.sys")
Inkey Str$("File size is %3f GB", edx::GfSize(-1)/1073741824)
  .else
Inkey "no such file"
  .endif
EndOfCode

File size is 4.39 GB (GfSize uses FindFirstFile instead of GetFileSize)

mikeburr

  • Member
  • **
  • Posts: 132
Re: Trouble with file length under Win64
« Reply #8 on: February 11, 2021, 12:59:12 AM »
jj
i think youve prob misunderstood what i wrote .. we can all see the params are incorrect ..
1) the question is whether create file succeeded with apparantly erroneous params [ hence the "not defined" comment ]
   id like to see what happens with invalidity testing in to see if it did work by chance
2) the file size if created implied a fairly substantial file overhead hence the first comment i made
  interested to hear about getfile though
regards mikeb
 

jj2007

  • Member
  • *****
  • Posts: 11306
  • Assembler is fun ;-)
    • MasmBasic
Re: Trouble with file length under Win64
« Reply #9 on: February 11, 2021, 01:06:49 AM »
For large files that are indeed accessible, the correct use of CreateFile+GetFileSize is as follows:
Code: [Select]
  mov hTheFile, rv(CreateFileA, Chr$("GetFileSize.asc"), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
  jinvoke GetFileSize, hTheFile, addr fsize ; point to a DWORD
  mov edx, fsize
  shl rdx, 32
  add rax, rdx
  Print Str$("The file size is %i bytes\n", rax)

As you rightly write, Mike, there is a certain overhead: CreateFile(); that's why GfSize() uses FindFirstFile under the hood, and can check the size of locked files, too.

How relevant that overhead is, that's another question :cool:
Code: [Select]
25 ms for 1000x CreateFile, GetFileSize and CloseHandle
25 ms for 1000x FindFirstFile and getting the size

22 ms for 1000x CreateFile, GetFileSize and CloseHandle
25 ms for 1000x FindFirstFile and getting the size

20 ms for 1000x CreateFile, GetFileSize and CloseHandle
24 ms for 1000x FindFirstFile and getting the size

21 ms for 1000x CreateFile, GetFileSize and CloseHandle
24 ms for 1000x FindFirstFile and getting the size

21 ms for 1000x CreateFile, GetFileSize and CloseHandle
25 ms for 1000x FindFirstFile and getting the size

TouEnMasm

  • Member
  • *****
  • Posts: 1615
    • EditMasm
Re: Trouble with file length under Win64
« Reply #10 on: February 11, 2021, 01:41:54 AM »

The createfile function don't give the size of the file.What you get is unitialised data.
use : FindFirstFile to get the size

Quote
         .data
InfosFiles WIN32_FIND_DATA <>
NomAediter db "\chose\myfle.txt",0
.code
          invoke FindFirstFile,addr NomAediter,addr InfosFiles
         mov edx,ex
         invoke FindClose,edx          ;close the search and now you have the size of the file in InfosFiles.nFileSizeLow



Fa is a musical note to play with CL

Gunther

  • Member
  • *****
  • Posts: 3720
  • Forgive your enemies, but never forget their names
Re: Trouble with file length under Win64
« Reply #11 on: February 11, 2021, 03:31:45 AM »
Timo,

Code: [Select]
uint64_format      db "%llu",0           ; 64 bit unsigned integer this might not be usable with msvcrt.dll,
have to use at least msvcr100.dll ?

you're right. It works fine with GCC's RTL, but not with msvcrt.dll. That's a real mess.

Erol,

Can you try this one ?

Code: [Select]
invoke     vc_printf, addr uint64_format, TheFileLen

 that doesn't help.

HSE,

[/quote]
A good practice (at least when something went wrong :biggrin: ) is:
Code: [Select]
invoke CreateFileA, addr TheFile, GENERIC_READ, 0, 0, 0, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING
.if eax!=INVALID_HANDLE_VALUE                       
        mov hTheFile, rax         ; save file handle
        ...
.else
       ; there is an error
.endif

Regards, HSE

yes, of course. But it's only a small test program, to show the problem. Right now, it looks like it's a mix of several factors. I'll get back when I know more.

Gunther
Get your facts first, and then you can distort them.

Gunther

  • Member
  • *****
  • Posts: 3720
  • Forgive your enemies, but never forget their names
Re: Trouble with file length under Win64
« Reply #12 on: February 11, 2021, 04:37:40 AM »
As I already suspected, it was a concatenation of various error causes. Once the order of the parameters was not correct. On the other hand, there were problems printing unsigned long long with msvcrt.dll.

I was able to correct all this and now the file length is correctly determined and printed. Thanks for the help.

Gunther

« Last Edit: February 11, 2021, 06:37:58 AM by Gunther »
Get your facts first, and then you can distort them.

TimoVJL

  • Member
  • ****
  • Posts: 695
Re: Trouble with file length under Win64
« Reply #13 on: February 11, 2021, 10:59:05 PM »
It works fine with GCC's RTL, but not with msvcrt.dll. That's a real mess.
M$ just wanted to do things in their own way in Steve Pallmer era, C99 standard wasn't in their list.
May the source be with you

Gunther

  • Member
  • *****
  • Posts: 3720
  • Forgive your enemies, but never forget their names
Re: Trouble with file length under Win64
« Reply #14 on: February 12, 2021, 12:35:38 AM »
Timo,

M$ just wanted to do things in their own way in Steve Pallmer era, C99 standard wasn't in their list.

that's right, but you can't just blame Ballmer, the gnat. Mr. Gates also has his share in this development.

Gunther
Get your facts first, and then you can distort them.