Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 459
  • Last Modified:

Problem with creating an empty/blank file above 1.16GB

So, i'm trying to create a file that is... lets say 2GB, but when i use the routine i wrote, the file is 1.16GB, how do i avoid this limit ?


procedure TDAPClass.CreateBlankFile(
const FilePath: String );
const
  TmpFileBuffer : Byte = ($00);
  dwFlagsAndAttr = FILE_FLAG_RANDOM_ACCESS;
var
  hTmpFile      : THandle;
  nBytesWritten : DWORD;
  I             : Integer;
begin
  // Create a temp blank file
  hTmpFile := CreateFile(
  PChar( FilePath ),
  GENERIC_WRITE,
  0,
  nil,
  CREATE_ALWAYS,
  FILE_ATTRIBUTE_TEMPORARY or dwFlagsAndAttr,
  0 );
  for I := 0 to Pred(nConnections) do
  begin
    // seek to given offset
    SetFilePointer(
     hTmpFile, i64EndOffset[I] - 1, nil, FILE_BEGIN );
    Sleep(500);
    // Write 1 byte in current offset
    WriteFile(
     hTmpFile, TmpFileBuffer, SizeOf(TmpFileBuffer), nBytesWritten, nil );
    Sleep(500);
  end;
  // Close Temp file handle
  CloseHandle( hTmpFile );
end;

Open in new window

0
rotem156
Asked:
rotem156
1 Solution
 
epasquierCommented:
SetFilePointer has a weird way of managing size parameters. It takes the size in 2 different ways :
- movement is a signed 32 bits integer, in first parameter after handle, second param not used (=nil) :
=> MAX = 2GB -1 .
So this method will fail if you try to put unsigned size equal or above 2GB.
- movement is a signed 64 bits integer : first param takes the low order part, and second parameter takes a pointer to the highest order part. That is the weird part, the pointer. See how I managed it in code.

You will ask as myself first did : why so complex ? why a pointer in 2nd parameter ? well, because if this was not a pointer, seeing that they made a single function with 2 functioning modes, you would have problem with 64 bits sizes between $80000000 (2GB) and $FFFFFFFF (4GB-1) because then high order part would be nul, AND first part would have to be considered SIGNED, not UNSIGNED.

Of course, they could have replaced all that with a single 64 bits signed value, even if that meant separate that in 2 params, but without pointer stuff and 2 functioning modes. But that would have broken existing 32bits only code using the API.

One last note : Delphi Seek & Truncate functions, which would be the equivalent of the method used below, have the same restriction with the 2GB-1 limit, or you'll end up with I/O error #131 :  ERROR_NEGATIVE_SEEK

Here is how to do that properly :

procedure CreateBlankFile(const FilePath: String; Size:int64 );
Var
 hTmpFile:THandle;
const
 dwFlagsAndAttr = FILE_FLAG_RANDOM_ACCESS;
begin
 hTmpFile := CreateFile( PChar( FilePath ),
  GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
  FILE_ATTRIBUTE_TEMPORARY or dwFlagsAndAttr, 0 );
 try
  if Size>=$80000000
   Then SetFilePointer( hTmpFile, Size {And $FFFFFFFF}, Pointer(Cardinal(@Size)+4), FILE_BEGIN )
   Else SetFilePointer( hTmpFile, Size, nil, FILE_BEGIN );
  SetEndOfFile( hTmpFile );
 finally
  CloseHandle( hTmpFile );
 end;
end;

Open in new window

0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now