News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Trouble with file length under Win64

Started by Gunther, February 10, 2021, 10:11:00 PM

Previous topic - Next topic

Gunther

Here is a small Win64 test program to determine the length of a file:

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
You have to know the facts before you can distort them.

jj2007

Check your parameters...

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:
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

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

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

Hi Gunther,

Can you try this one ?

invoke     vc_printf, addr uint64_format, TheFileLen

HSE

Hi Gunther,

A good practice (at least when something went wrong :biggrin: ) is: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
Equations in Assembly: SmplMath

mikeburr

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

Quote from: jj2007 on February 10, 2021, 10:46:18 PM
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:
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

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

For large files that are indeed accessible, the correct use of CreateFile+GetFileSize is as follows:
  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:
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


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

Timo,

Quote from: TimoVJL on February 10, 2021, 11:55:08 PM
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,

Quote from: Vortex on February 10, 2021, 11:58:39 PM
Can you try this one ?

invoke     vc_printf, addr uint64_format, TheFileLen

that doesn't help.

HSE,

[/quote]
Quote from: HSE on February 11, 2021, 12:17:12 AM
A good practice (at least when something went wrong :biggrin: ) is: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
You have to know the facts before you can distort them.

Gunther

#12
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

You have to know the facts before you can distort them.

TimoVJL

Quote from: Gunther on February 11, 2021, 03:31:45 AM
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

Timo,

Quote from: TimoVJL on February 11, 2021, 10:59:05 PM
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
You have to know the facts before you can distort them.