You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
417 lines
11 KiB
417 lines
11 KiB
5 years ago
|
//========= 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;
|
||
|
}
|