source-engine/utils/xbox/vxconsole/fileio.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

417 lines
11 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// FILEIO.CPP
//
// File I/O Service Routines
//=====================================================================================//
#include "vxconsole.h"
//-----------------------------------------------------------------------------
// SystemTimeToString
//
// mm/dd/yyyy hh:mm:ss am
//-----------------------------------------------------------------------------
char *SystemTimeToString( SYSTEMTIME *systemTime, char *buffer, int bufferSize )
{
char timeString[256];
char dateString[256];
int length;
GetDateFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "MM'/'dd'/'yyyy", dateString, sizeof( dateString ) );
GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "hh':'mm':'ss tt", timeString, sizeof( timeString ) );
length = _snprintf( buffer, bufferSize, "%s %s", dateString, timeString );
if ( length == -1 )
buffer[bufferSize-1] = '\0';
return buffer;
}
//-----------------------------------------------------------------------------
// CompareFileTimes_NTFStoFATX
//
//-----------------------------------------------------------------------------
int CompareFileTimes_NTFStoFATX( FILETIME* ntfsFileTime, char *ntfsTimeString, int ntfsStringSize, FILETIME* fatxFileTime, char *fatxTimeString, int fatxStringSize )
{
SYSTEMTIME ntfsSystemTime;
SYSTEMTIME fatxSystemTime;
int diff;
int ntfsSeconds;
int fatxSeconds;
TIME_ZONE_INFORMATION tzInfo;
GetTimeZoneInformation( &tzInfo );
// cannot compare UTC file times directly
// disjoint filesystems - xbox has a +/- 2s error
// daylight savings time handling on each file system may cause problems
FileTimeToSystemTime( ntfsFileTime, &ntfsSystemTime );
FileTimeToSystemTime( fatxFileTime, &fatxSystemTime );
// operate on local times, assumes xbox and pc are both set for same time zone and daylight saving
SYSTEMTIME ntfsLocalTime;
SYSTEMTIME fatxLocalTime;
SystemTimeToTzSpecificLocalTime( &tzInfo, &ntfsSystemTime, &ntfsLocalTime );
SystemTimeToTzSpecificLocalTime( &tzInfo, &fatxSystemTime, &fatxLocalTime );
if ( ntfsTimeString )
{
SystemTimeToString( &ntfsLocalTime, ntfsTimeString, ntfsStringSize );
}
if ( fatxTimeString )
{
SystemTimeToString( &fatxLocalTime, fatxTimeString, fatxStringSize );
}
diff = ntfsLocalTime.wYear-fatxLocalTime.wYear;
if ( diff )
return diff;
diff = ntfsLocalTime.wMonth-fatxLocalTime.wMonth;
if ( diff )
return diff;
diff = ntfsLocalTime.wDay-fatxLocalTime.wDay;
if ( diff )
return diff;
diff = ntfsLocalTime.wHour-fatxLocalTime.wHour;
if ( diff )
return diff;
// allow for +/- 3s error
ntfsSeconds = ntfsLocalTime.wHour*60*60 + ntfsLocalTime.wMinute*60 + ntfsLocalTime.wSecond;
fatxSeconds = fatxLocalTime.wHour*60*60 + fatxLocalTime.wMinute*60 + fatxLocalTime.wSecond;
diff = ntfsSeconds-fatxSeconds;
if ( diff > 3 || diff < -3 )
return diff;
// times are considered equal
return 0;
}
//-----------------------------------------------------------------------------
// FreeTargetFileList
//
//-----------------------------------------------------------------------------
void FreeTargetFileList( fileNode_t* pFileList )
{
fileNode_t *nodePtr;
fileNode_t *nextPtr;
if ( !pFileList )
return;
nodePtr = pFileList;
while ( nodePtr )
{
nextPtr = nodePtr->nextPtr;
Sys_Free( nodePtr->filename );
Sys_Free( nodePtr );
nodePtr = nextPtr;
}
}
//-----------------------------------------------------------------------------
// GetTargetFileList_r
//
//-----------------------------------------------------------------------------
bool GetTargetFileList_r( char* targetPath, bool recurse, int attributes, int level, fileNode_t** pFileList )
{
HRESULT hr;
PDM_WALK_DIR pWalkDir = NULL;
DM_FILE_ATTRIBUTES fileAttr;
bool valid;
char filename[MAX_PATH];
fileNode_t* nodePtr;
bool bGetNormal;
int fixedAttributes;
if ( !level )
*pFileList = NULL;
fixedAttributes = attributes;
if ( fixedAttributes & FILE_ATTRIBUTE_NORMAL )
{
fixedAttributes &= ~FILE_ATTRIBUTE_NORMAL;
bGetNormal = true;
}
else
bGetNormal = false;
while ( 1 )
{
hr = DmWalkDir( &pWalkDir, targetPath, &fileAttr );
if ( hr != XBDM_NOERR )
break;
strcpy( filename, targetPath );
Sys_AddFileSeperator( filename, sizeof( filename ) );
strcat( filename, fileAttr.Name );
// restrict to desired attributes
if ( ( bGetNormal && !fileAttr.Attributes ) || ( fileAttr.Attributes & fixedAttributes ) )
{
Sys_NormalizePath( filename, false );
// create a new file node
nodePtr = ( fileNode_t* )Sys_Alloc( sizeof( fileNode_t ) );
// link it in
nodePtr->filename = Sys_CopyString( filename );
nodePtr->changeTime = fileAttr.ChangeTime;
nodePtr->creationTime = fileAttr.CreationTime;
nodePtr->sizeHigh = fileAttr.SizeHigh;
nodePtr->sizeLow = fileAttr.SizeLow;
nodePtr->attributes = fileAttr.Attributes;
nodePtr->level = level;
nodePtr->nextPtr = *pFileList;
*pFileList = nodePtr;
}
if ( fileAttr.Attributes & FILE_ATTRIBUTE_DIRECTORY )
{
if ( recurse )
{
// descend into directory
valid = GetTargetFileList_r( filename, recurse, attributes, level+1, pFileList );
if ( !valid )
return false;
}
}
}
DmCloseDir( pWalkDir );
if ( hr != XBDM_ENDOFLIST )
{
// failure
return false;
}
// ok
return true;
}
//-----------------------------------------------------------------------------
// FileSyncEx
//
// -1: failure, 0: nothing, 1: synced
//-----------------------------------------------------------------------------
int FileSyncEx( const char* localFilename, const char* targetFilename, int fileSyncMode, bool bVerbose, bool bNoWrite )
{
bool copy;
bool pathExist;
WIN32_FILE_ATTRIBUTE_DATA localAttributes;
DM_FILE_ATTRIBUTES targetAttributes;
HRESULT hr;
int errCode;
int deltaTime;
char localTimeString[256];
char targetTimeString[256];
if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_OFF )
{
return 0;
}
if ( !GetFileAttributesEx( localFilename, GetFileExInfoStandard, &localAttributes ) )
{
// failed to get the local file's attributes
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failure: Local file %s not available\n", localFilename );
}
return -1;
}
if ( localAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
// ignore directory
return 0;
}
if ( fileSyncMode & FSYNC_ANDEXISTSONTARGET )
{
hr = DmGetFileAttributes( targetFilename, &targetAttributes );
if ( hr != XBDM_NOERR )
{
// target doesn't exist, no sync operation should commence
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, Target file %s not available\n", targetFilename );
}
return 0;
}
}
// default success, no operation
errCode = 0;
// default, create path and copy
copy = true;
pathExist = false;
if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_IFNEWER )
{
hr = DmGetFileAttributes( targetFilename, &targetAttributes );
if ( hr == XBDM_NOERR )
{
// target path to file exists
pathExist = true;
// compare times
deltaTime = CompareFileTimes_NTFStoFATX( &localAttributes.ftLastWriteTime, localTimeString, sizeof( localTimeString), &targetAttributes.ChangeTime, targetTimeString, sizeof( targetTimeString ) );
if ( deltaTime < 0 )
{
// ntfs is older, fatx is newer, no update
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] is newer than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString );
}
copy = false;
}
else if ( !deltaTime )
{
// equal times, compare sizes
if ( localAttributes.nFileSizeLow == targetAttributes.SizeLow &&
localAttributes.nFileSizeHigh == targetAttributes.SizeHigh )
{
// file appears synced
copy = false;
}
if ( bVerbose )
{
if ( copy )
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] [%d] has different size than %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow );
}
else
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] [%d] has same time and file size as %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow );
}
}
}
else
{
// ntfs is newer, fatx is older, update
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] is older than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString );
}
}
}
}
else if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_ALWAYS )
{
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Force Update, %s\n", targetFilename );
}
}
if ( copy && !bNoWrite )
{
if ( !pathExist )
{
CreateTargetPath( targetFilename );
}
hr = DmSendFile( localFilename, targetFilename );
if ( hr == XBDM_NOERR )
{
// force the target to match the local attributes
// to ensure sync
memset( &targetAttributes, 0, sizeof( targetAttributes ) );
targetAttributes.SizeHigh = localAttributes.nFileSizeHigh;
targetAttributes.SizeLow = localAttributes.nFileSizeLow;
targetAttributes.CreationTime = localAttributes.ftCreationTime;
targetAttributes.ChangeTime = localAttributes.ftLastWriteTime;
DmSetFileAttributes( targetFilename, &targetAttributes );
// success, file copied
errCode = 1;
}
else
{
// failure
if ( bVerbose )
{
ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failed!\n" );
}
errCode = -1;
}
DebugCommand( "0x%8.8x = FileSyncEx( %s, %s )\n", hr, localFilename, targetFilename );
}
return errCode;
}
//-----------------------------------------------------------------------------
// LoadTargetFile
//
//-----------------------------------------------------------------------------
bool LoadTargetFile( const char *pTargetPath, int *pFileSize, void **pData )
{
DM_FILE_ATTRIBUTES fileAttributes;
HRESULT hr;
DWORD bytesRead;
char *pBuffer;
*pFileSize = 0;
*pData = (void *)NULL;
hr = DmGetFileAttributes( pTargetPath, &fileAttributes );
if ( hr != XBDM_NOERR || !fileAttributes.SizeLow )
return false;
// allocate for size and terminating null
pBuffer = (char *)Sys_Alloc( fileAttributes.SizeLow+1 );
hr = DmReadFilePartial( pTargetPath, 0, (LPBYTE)pBuffer, fileAttributes.SizeLow, &bytesRead );
if ( hr != XBDM_NOERR || ( bytesRead != fileAttributes.SizeLow ) )
{
Sys_Free( pBuffer );
return false;
}
// add a terminating null
pBuffer[fileAttributes.SizeLow] = '\0';
*pFileSize = fileAttributes.SizeLow;
*pData = pBuffer;
// success
return true;
}
//-----------------------------------------------------------------------------
// CreateTargetPath
//
//-----------------------------------------------------------------------------
bool CreateTargetPath( const char *pTargetFilename )
{
// create path chain
char *pPath;
char dirPath[MAX_PATH];
// prime and skip to first seperator
strcpy( dirPath, pTargetFilename );
pPath = strchr( dirPath, '\\' );
while ( pPath )
{
pPath = strchr( pPath+1, '\\' );
if ( pPath )
{
*pPath = '\0';
DmMkdir( dirPath );
*pPath = '\\';
}
}
return true;
}