Skip to content

Commit

Permalink
Add support for 64 bit file sizes
Browse files Browse the repository at this point in the history
The TEntry.iSize field is now a 64 bit integer, and is filled out
correctly on all platforms apart from Amiga OS.  This was implemented
to support transferring of files larger than 4GB in RADRunner.  Methods
that use this field, such as the Yggdrasil support methods, have also
been updated.
  • Loading branch information
Colin Ward authored and hitman-codehq committed Sep 8, 2023
1 parent 8df89fe commit 3e4aeaf
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 27 deletions.
8 changes: 4 additions & 4 deletions Dir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,11 @@ void TEntry::Reset()

/* Written: Saturday 03-Nov-2007 6:42 pm */

void TEntry::Set(TBool a_bIsDir, TBool a_bIsLink, TUint a_uiSize, TUint a_uiAttributes, const TDateTime &a_roDateTime)
void TEntry::Set(TBool a_bIsDir, TBool a_bIsLink, TInt64 a_iSize, TUint a_uiAttributes, const TDateTime &a_roDateTime)
{
iIsDir = a_bIsDir;
iIsLink = a_bIsLink;
iSize = a_uiSize;
iSize = a_iSize;
iAttributes = a_uiAttributes;
iModified = a_roDateTime;

Expand Down Expand Up @@ -401,11 +401,11 @@ TInt TEntryArray::CompareEntries(const TEntry *a_poFirst, const TEntry *a_poSeco
}
else if (SortInfo->m_eSortOrder == EDirSortSizeAscending)
{
RetVal = (a_poFirst->iSize - a_poSecond->iSize);
RetVal = static_cast<TInt>(a_poFirst->iSize - a_poSecond->iSize);
}
else if (SortInfo->m_eSortOrder == EDirSortSizeDescending)
{
RetVal = (a_poSecond->iSize - a_poFirst->iSize);
RetVal = static_cast<TInt>(a_poSecond->iSize - a_poFirst->iSize);
}
else if (SortInfo->m_eSortOrder == EDirSortDateAscending)
{
Expand Down
4 changes: 2 additions & 2 deletions Dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class TEntry
filled out by Utils::GetFileInfo(), not by methods in RDir */
TBool iIsDir; /**< ETrue if entry is a directory */
TBool iIsLink; /**< ETrue if entry is a link */
TUint iSize; /**< File size in bytes */
TInt64 iSize; /**< File size in bytes */
TUint iAttributes; /**< Protection attributes, in Amiga/UNIX/Windows format */
TTime iModified; /**< Time and date of the file */

Expand Down Expand Up @@ -81,7 +81,7 @@ class TEntry

void Reset();

void Set(TBool a_bIsDir, TBool a_bIsLink, TUint a_uiSize, TUint a_uiAttributes, const TDateTime &a_oDateTime);
void Set(TBool a_bIsDir, TBool a_bIsLink, TInt64 a_iSize, TUint a_uiAttributes, const TDateTime &a_oDateTime);
};

/* An instance of this class represents a number of TEntry classes and is filled */
Expand Down
8 changes: 8 additions & 0 deletions MungWall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ void *MungWall::New(size_t stSize, const char *pccSourceFile, int iSourceLine)
void *pvRetVal = NULL;
struct Arena *paBlock;

/* Account for the wraparound that will happen on 32 bit systems, if someone tries to allocate a */
/* very large amount of memory, such as 0xffffffff bytes */

if (stMungedSize < stSize)
{
return(NULL);
}

if (bEnableProfiling)
{
++ulNumProfiledNews;
Expand Down
2 changes: 1 addition & 1 deletion RemoteFileUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ int RRemoteFileUtils::getFileInfo(const char *a_fileName, TEntry *a_entry)
{
SFileInfo *fileInfo = reinterpret_cast<SFileInfo *>(handler->getResponsePayload());
SWAP64(&fileInfo->m_microseconds);
SWAP(&fileInfo->m_size);
SWAP64(&fileInfo->m_size);

TDateTime dateTime(fileInfo->m_microseconds);

Expand Down
12 changes: 11 additions & 1 deletion StdConfigFile.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

#include "StdFuncs.h"
#include <limits.h>
#include <string.h>
#include "File.h"
#include "Lex.h"
Expand Down Expand Up @@ -252,10 +253,14 @@ CKey *CSection::FindNextKey(CKey *a_poKey, const char *a_pccName)
* Opens a configuration file, reads its contents into memory and parses it in preparation
* for querying by the section, group and key querying functions.
*
* This convenience method is not meant for reading enormous files, and will fail for files
* of size larger than INT_MAX bytes.
*
* @date Wednesday 22-Apr-1998 9:33 pm
* @param a_pccFileName Name of configuration file to open
* @return KErrNone if successful
* @return KErrNoMemory if there was not enough memory to read the file
* @return KErrNotSupported if the file was too large to be read
* @return KErrEof if the file could be opened but not completely read
* @return Any error from Utils::GetFileInfo()
* @return Any error from RFile::open()
Expand All @@ -271,7 +276,12 @@ TInt RConfigFile::open(const char *a_pccFileName)

if ((RetVal = Utils::GetFileInfo(a_pccFileName, &Entry)) == KErrNone)
{
m_iBufferSize = Entry.iSize;
if (Entry.iSize > INT_MAX)
{
return(KErrNotSupported);
}

m_iBufferSize = static_cast<int>(Entry.iSize);

if ((m_pcBuffer = new char[m_iBufferSize]) != NULL)
{
Expand Down
25 changes: 20 additions & 5 deletions Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#ifdef __amigaos__

#include <limits.h>
#include <clib/debug_protos.h>
#include <dos/dostags.h>
#include <proto/intuition.h>
Expand Down Expand Up @@ -1191,10 +1192,13 @@ TInt Utils::GetFileInfo(const char *a_pccFileName, TEntry *a_poEntry, TBool a_bR
TDateTime DateTime(ClockData.year, (TMonth) (ClockData.month - 1), ClockData.mday, ClockData.hour,
ClockData.min, ClockData.sec, 0);

/* And populate the new TEntry instance with information about the file or directory */
/* And populate the new TEntry instance with information about the file or directory. */
/* We cast fib_Size to a TUint as fib_Size is a signed 32 bit integer, but it contains a */
/* valid unsigned 32 bit size of the file, up to 0xffffffff bytes. On 64 bit filesystems */
/* files larger than 4GB will have their size set to this */

a_poEntry->Set((FileInfoBlock->fib_DirEntryType > 0), TYPE_IS_LINK(FileInfoBlock->fib_DirEntryType),
FileInfoBlock->fib_Size, FileInfoBlock->fib_Protection, DateTime);
(TUint) FileInfoBlock->fib_Size, FileInfoBlock->fib_Protection, DateTime);
a_poEntry->iPlatformDate = FileInfoBlock->fib_Date;

/* If the name of the directory is the special case of an Amiga OS volume then return just */
Expand Down Expand Up @@ -1334,7 +1338,7 @@ TInt Utils::GetFileInfo(const char *a_pccFileName, TEntry *a_poEntry, TBool a_bR
/* Fill in the file's properties in the TEntry structure */

a_poEntry->Set((FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY), (FileInformation.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT),
FileInformation.nFileSizeLow, FileInformation.dwFileAttributes, DateTime);
(TInt64) FileInformation.nFileSizeHigh << 32 | FileInformation.nFileSizeLow, FileInformation.dwFileAttributes, DateTime);
a_poEntry->iPlatformDate = FileInformation.ftLastWriteTime;

/* Try to find the file so that we can obtain its "real" name, which may vary by case */
Expand Down Expand Up @@ -1868,11 +1872,15 @@ void Utils::info(const char *a_pccMessage, ...)
* the user to delete [] this memory. If the function fails to load the file, a_ppucBuffer will
* be set to NULL.
*
* This convenience method is not meant for reading enormous files, and will fail for files of
* size larger than INT_MAX bytes.
*
* @param a_pccFileName Pointer to the name of the file to be opened
* @param a_ppucBuffer Pointer to a variable into which to place the pointer to the allocated
* buffer
* @return The size of the file in bytes, not including the NULL terminator, if successful
* @return KErrNoMemory if not enough memory was available
* @return KErrNotSupported if the file was too large to be read
* @return Otherwise any of the errors returned by Utils::GetFileInfo(), RFile::open() or
* RFile::read()
*/
Expand All @@ -1883,6 +1891,8 @@ TInt Utils::LoadFile(const char *a_pccFileName, unsigned char **a_ppucBuffer)
TInt RetVal;
TEntry Entry;

ASSERTM((a_ppucBuffer != NULL), "Utils::LoadFile() => Buffer passed in must not be NULL");

/* Assume failure */

*a_ppucBuffer = NULL;
Expand All @@ -1891,17 +1901,22 @@ TInt Utils::LoadFile(const char *a_pccFileName, unsigned char **a_ppucBuffer)

if ((RetVal = Utils::GetFileInfo(a_pccFileName, &Entry)) == KErrNone)
{
if (Entry.iSize > INT_MAX)
{
return(KErrNotSupported);
}

/* Allocate a buffer of the appropriate size */

if ((Buffer = new unsigned char[Entry.iSize + 1]) != NULL)
if ((Buffer = new unsigned char[static_cast<size_t>(Entry.iSize + 1)]) != NULL)
{
RFile File;

/* Open the file and read its contents into the buffer */

if ((RetVal = File.open(a_pccFileName, EFileRead)) == KErrNone)
{
if ((RetVal = File.read(Buffer, Entry.iSize)) == (TInt) Entry.iSize)
if ((RetVal = File.read(Buffer, (TInt) Entry.iSize)) == (TInt) Entry.iSize)
{
/* NULL terminate the buffer and save its pointer for the calling client */

Expand Down
2 changes: 1 addition & 1 deletion Yggdrasil/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ struct SFileInfo
TInt64 m_microseconds; /**< Timestamp of the file, in microseconds since 01.01.01 */
unsigned int m_isDir; /**< True if the file system object is a directory */
unsigned int m_isLink; /**< True if the file system object is a link */
unsigned int m_size; /**< File size in bytes */
TInt64 m_size; /**< File size in bytes */
char m_fileName[1]; /**< The file's name, without a path component */
};

Expand Down
29 changes: 16 additions & 13 deletions Yggdrasil/Handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ int CHandler::getFileInformation(const char *a_fileName, SFileInfo *&a_fileInfo)
a_fileInfo->m_isLink = entry.iIsLink;

a_fileInfo->m_size = entry.iSize;
SWAP(&a_fileInfo->m_size);
SWAP64(&a_fileInfo->m_size);
}

return retVal;
Expand All @@ -92,13 +92,13 @@ int CHandler::getFileInformation(const char *a_fileName, SFileInfo *&a_fileInfo)

int CHandler::readFile(const char *a_fileName)
{
uint32_t fileSize;
TInt64 fileSize;
RFile file;

m_socket->read(&fileSize, sizeof(fileSize));
SWAP(&fileSize);
SWAP64(&fileSize);

printf("%s: Transferring file \"%s\" of size %u\n", g_commandNames[m_command.m_command], a_fileName, fileSize);
printf("%s: Transferring file \"%s\"\n", g_commandNames[m_command.m_command], a_fileName);

/* The Framework doesn't truncate a file if it already exists, so delete any existing file before continuing */
/* to avoid creating non working executables */
Expand All @@ -111,7 +111,8 @@ int CHandler::readFile(const char *a_fileName)
if (retVal == KErrNone)
{
int result;
uint32_t bytesRead = 0, bytesToRead, size;
uint32_t bytesToRead, size;
TInt64 bytesRead = 0;
unsigned char *buffer = new unsigned char[TRANSFER_SIZE];

/* Determine the start time so that it can be used to calculate the amount of time the transfer took */
Expand All @@ -121,7 +122,7 @@ int CHandler::readFile(const char *a_fileName)

do
{
bytesToRead = ((fileSize - bytesRead) >= TRANSFER_SIZE) ? TRANSFER_SIZE : (fileSize - bytesRead);
bytesToRead = ((fileSize - bytesRead) >= TRANSFER_SIZE) ? TRANSFER_SIZE : static_cast<uint32_t>(fileSize - bytesRead);
size = m_socket->read(buffer, bytesToRead);

/* Write to write the received information to the target file. If this fails, we have to continue with */
Expand All @@ -143,8 +144,9 @@ int CHandler::readFile(const char *a_fileName)
if (retVal == KErrNone)
{
/* Cast the time results to integers when printing as Amiga OS doesn't support 64 bit format specifiers */
printf("%s: Wrote %d.%d Kilobytes to file \"%s\" in %d.%d seconds\n", g_commandNames[m_command.m_command], (bytesRead / 1024),
(bytesRead % 1024), a_fileName, static_cast<int>(total / 1000), static_cast<int>(total % 1000));
printf("%s: Wrote %d.%d Kilobytes to file \"%s\" in %d.%d seconds\n", g_commandNames[m_command.m_command],
static_cast<int>(bytesRead / 1024), static_cast<int>(bytesRead % 1024),
a_fileName, static_cast<int>(total / 1000), static_cast<int>(total % 1000));
}
else
{
Expand Down Expand Up @@ -248,8 +250,8 @@ int CHandler::sendFile(const char *a_fileName)

if ((retVal = Utils::GetFileInfo(a_fileName, &entry)) == KErrNone)
{
int fileSize = entry.iSize;
SWAP(&fileSize);
TInt64 fileSize = entry.iSize;
SWAP64(&fileSize);

m_socket->write(&fileSize, sizeof(fileSize));

Expand Down Expand Up @@ -277,9 +279,10 @@ int CHandler::sendFile(const char *a_fileName)
TInt64 endTime = now.Int64();
TInt64 total = ((endTime - startTime) / 1000);

/* Cast the time results to integers when printing as Amiga OS doesn't support 64 bit format specifiers */
printf("%s: Transferred %u.%u Kilobytes in %d.%d seconds\n", g_commandNames[m_command.m_command], (entry.iSize / 1024),
(entry.iSize % 1024), static_cast<int>(total / 1000), static_cast<int>(total % 1000));
/* Cast 64 bit results to integers when printing as Amiga OS doesn't support 64 bit format specifiers */
printf("%s: Transferred %d.%d Kilobytes in %d.%d seconds\n", g_commandNames[m_command.m_command],
static_cast<int>(entry.iSize / 1024), static_cast<int>(entry.iSize % 1024),
static_cast<int>(total / 1000), static_cast<int>(total % 1000));

delete [] buffer;
}
Expand Down

0 comments on commit 3e4aeaf

Please sign in to comment.